From 5cec4cfde4c18df1e3defe7086c8fea1e4b54e37 Mon Sep 17 00:00:00 2001 From: Katrix Date: Thu, 17 Jun 2021 17:09:57 +0200 Subject: [PATCH 01/32] Divide sources into Scala 2 and 3 folders. Everything "compiles" --- build.sbt | 73 +- .../shapeless/CachedImplicitMacros.scala | 58 ++ .../shapeless/MacroState.scala | 0 .../main/scala-2/shapeless/annotation.scala | 213 +++++ .../main/scala-2/shapeless/coproduct.scala | 38 + core/src/main/scala-2/shapeless/default.scala | 87 ++ core/src/main/scala-2/shapeless/generic.scala | 807 ++++++++++++++++++ .../src/main/scala-2/shapeless/generic1.scala | 291 +++++++ core/src/main/scala-2/shapeless/hlists.scala | 161 ++++ .../src/main/scala-2/shapeless/labelled.scala | 121 +++ core/src/main/scala-2/shapeless/lazy.scala | 5 + core/src/main/scala-2/shapeless/nat.scala | 78 ++ core/src/main/scala-2/shapeless/ops/nat.scala | 53 ++ .../shapeless/ops/record/records.scala | 146 ++++ core/src/main/scala-2/shapeless/poly.scala | 55 ++ core/src/main/scala-2/shapeless/records.scala | 108 +++ .../main/scala-2/shapeless/singletons.scala | 250 ++++++ .../shapeless/test/compiletime.scala | 0 .../shapeless/test/package.scala | 0 .../shapeless/test/typechecking.scala | 0 .../shapeless/test/typetrace.scala | 0 .../src/main/scala-2/shapeless/typeable.scala | 149 ++++ .../scala-2/shapeless/typeoperators.scala | 79 ++ core/src/main/scala-2/shapeless/unions.scala | 58 ++ .../main/scala-3/shapeless/annotation.scala | 38 + .../main/scala-3/shapeless/coproduct.scala | 36 + core/src/main/scala-3/shapeless/default.scala | 5 + core/src/main/scala-3/shapeless/generic.scala | 39 + .../src/main/scala-3/shapeless/generic1.scala | 73 ++ core/src/main/scala-3/shapeless/hlists.scala | 52 ++ .../src/main/scala-3/shapeless/labelled.scala | 22 + core/src/main/scala-3/shapeless/lazy.scala | 5 + core/src/main/scala-3/shapeless/nat.scala | 21 + core/src/main/scala-3/shapeless/ops/nat.scala | 22 + .../shapeless/ops/record/records.scala | 41 + core/src/main/scala-3/shapeless/poly.scala | 26 + core/src/main/scala-3/shapeless/records.scala | 32 + .../main/scala-3/shapeless/singletons.scala | 35 + .../src/main/scala-3/shapeless/typeable.scala | 21 + .../scala-3/shapeless/typeoperators.scala | 11 + core/src/main/scala-3/shapeless/unions.scala | 22 + .../scala-3/shapeless/versionspecifics.scala | 51 ++ core/src/main/scala/shapeless/alacarte.scala | 36 +- .../src/main/scala/shapeless/annotation.scala | 196 +---- .../main/scala/shapeless/conversions.scala | 4 +- core/src/main/scala/shapeless/coproduct.scala | 23 +- core/src/main/scala/shapeless/default.scala | 86 +- core/src/main/scala/shapeless/generic.scala | 788 +---------------- core/src/main/scala/shapeless/generic1.scala | 270 +----- core/src/main/scala/shapeless/hlists.scala | 143 +--- core/src/main/scala/shapeless/hmap.scala | 2 +- core/src/main/scala/shapeless/labelled.scala | 103 +-- core/src/main/scala/shapeless/lazy.scala | 4 +- core/src/main/scala/shapeless/lenses.scala | 11 +- core/src/main/scala/shapeless/nat.scala | 62 +- .../src/main/scala/shapeless/ops/hlists.scala | 26 +- core/src/main/scala/shapeless/ops/nat.scala | 50 +- .../main/scala/shapeless/ops/records.scala | 125 +-- .../scala/shapeless/ops/traversables.scala | 4 +- .../src/main/scala/shapeless/ops/tuples.scala | 4 +- .../src/main/scala/shapeless/ops/zipper.scala | 2 +- core/src/main/scala/shapeless/package.scala | 67 +- core/src/main/scala/shapeless/poly.scala | 62 +- core/src/main/scala/shapeless/records.scala | 91 +- .../src/main/scala/shapeless/singletons.scala | 230 +---- .../main/scala/shapeless/syntax/sized.scala | 4 +- .../shapeless/syntax/std/functions.scala | 4 +- .../scala/shapeless/syntax/std/maps.scala | 2 +- .../shapeless/syntax/std/traversables.scala | 6 +- .../main/scala/shapeless/syntax/zipper.scala | 4 +- core/src/main/scala/shapeless/typeable.scala | 144 +--- .../main/scala/shapeless/typeoperators.scala | 85 +- core/src/main/scala/shapeless/unions.scala | 41 +- core/src/main/scala/shapeless/unwrapped.scala | 11 +- .../shapeless/versionspecifics.scala | 3 + .../shapeless/versionspecifics.scala | 2 + project/Boilerplate.scala | 2 +- 77 files changed, 3504 insertions(+), 2575 deletions(-) create mode 100644 core/src/main/scala-2/shapeless/CachedImplicitMacros.scala rename core/src/main/{scala => scala-2}/shapeless/MacroState.scala (100%) create mode 100644 core/src/main/scala-2/shapeless/annotation.scala create mode 100644 core/src/main/scala-2/shapeless/coproduct.scala create mode 100644 core/src/main/scala-2/shapeless/default.scala create mode 100644 core/src/main/scala-2/shapeless/generic.scala create mode 100644 core/src/main/scala-2/shapeless/generic1.scala create mode 100644 core/src/main/scala-2/shapeless/hlists.scala create mode 100644 core/src/main/scala-2/shapeless/labelled.scala create mode 100644 core/src/main/scala-2/shapeless/lazy.scala create mode 100644 core/src/main/scala-2/shapeless/nat.scala create mode 100644 core/src/main/scala-2/shapeless/ops/nat.scala create mode 100644 core/src/main/scala-2/shapeless/ops/record/records.scala create mode 100644 core/src/main/scala-2/shapeless/poly.scala create mode 100644 core/src/main/scala-2/shapeless/records.scala create mode 100644 core/src/main/scala-2/shapeless/singletons.scala rename core/src/main/{scala => scala-2}/shapeless/test/compiletime.scala (100%) rename core/src/main/{scala => scala-2}/shapeless/test/package.scala (100%) rename core/src/main/{scala => scala-2}/shapeless/test/typechecking.scala (100%) rename core/src/main/{scala => scala-2}/shapeless/test/typetrace.scala (100%) create mode 100644 core/src/main/scala-2/shapeless/typeable.scala create mode 100644 core/src/main/scala-2/shapeless/typeoperators.scala create mode 100644 core/src/main/scala-2/shapeless/unions.scala create mode 100644 core/src/main/scala-3/shapeless/annotation.scala create mode 100644 core/src/main/scala-3/shapeless/coproduct.scala create mode 100644 core/src/main/scala-3/shapeless/default.scala create mode 100644 core/src/main/scala-3/shapeless/generic.scala create mode 100644 core/src/main/scala-3/shapeless/generic1.scala create mode 100644 core/src/main/scala-3/shapeless/hlists.scala create mode 100644 core/src/main/scala-3/shapeless/labelled.scala create mode 100644 core/src/main/scala-3/shapeless/lazy.scala create mode 100644 core/src/main/scala-3/shapeless/nat.scala create mode 100644 core/src/main/scala-3/shapeless/ops/nat.scala create mode 100644 core/src/main/scala-3/shapeless/ops/record/records.scala create mode 100644 core/src/main/scala-3/shapeless/poly.scala create mode 100644 core/src/main/scala-3/shapeless/records.scala create mode 100644 core/src/main/scala-3/shapeless/singletons.scala create mode 100644 core/src/main/scala-3/shapeless/typeable.scala create mode 100644 core/src/main/scala-3/shapeless/typeoperators.scala create mode 100644 core/src/main/scala-3/shapeless/unions.scala create mode 100644 core/src/main/scala-3/shapeless/versionspecifics.scala diff --git a/build.sbt b/build.sbt index 020a5cb67..9cb9f32cf 100644 --- a/build.sbt +++ b/build.sbt @@ -3,6 +3,7 @@ import sbtcrossproject.CrossProject val Scala212 = "2.12.14" val Scala213 = "2.13.6" +val scala3 = "3.0.0" commonSettings noPublishSettings @@ -10,7 +11,7 @@ crossScalaVersions := Nil ThisBuild / organization := "com.chuusai" ThisBuild / scalaVersion := Scala213 -ThisBuild / crossScalaVersions := Seq(Scala212, Scala213) +ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, scala3) ThisBuild / mimaFailOnNoPrevious := false // GHA configuration @@ -54,7 +55,7 @@ ThisBuild / githubWorkflowPublish := Seq( ) ) -Global / excludeLintKeys += coreNative / packageDoc / publishArtifact +//TODO Global / excludeLintKeys += coreNative / packageDoc / publishArtifact addCommandAlias("root", ";project shapeless") addCommandAlias("core", ";project coreJVM") @@ -67,34 +68,46 @@ addCommandAlias("validateJS", ";coreJS/compile;coreJS/mimaReportBinaryIssues;cor addCommandAlias("validateNative", ";coreNative/compile;nativeTest/run;examplesNative/compile") addCommandAlias("runAll", ";examplesJVM/runAll") -def scalacOptionsAll(pluginJar: File) = List( +val scalacOptionsAll = List( "-feature", "-language:higherKinds,implicitConversions", "-Xfatal-warnings", "-deprecation", - "-unchecked", + "-unchecked" +) + +def scalacOptions2(pluginJar: File) = List( s"-Xplugin:${pluginJar.getAbsolutePath}", s"-Jdummy=${pluginJar.lastModified}" ) -val scalacOptions212 = Seq( +val scalacOptions3 = Seq( + "-language:dynamics", +) + +def scalacOptions212(pluginJar: File) = Seq( "-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,_", "-Ywarn-unused:-implicits" -) +) ++ scalacOptions2(pluginJar) -val scalacOptions213 = Seq( +def scalacOptions213(pluginJar: File) = Seq( "-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,-byname-implicit,_", "-Ywarn-unused:-implicits" -) +) ++ scalacOptions2(pluginJar) lazy val commonSettings = Seq( incOptions := incOptions.value.withLogRecompileOnMacro(false), - scalacOptions := scalacOptionsAll((plugin / Compile / packageBin).value), + scalacOptions := scalacOptionsAll, Compile / compile / scalacOptions ++= (CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 12)) => scalacOptions212 - case Some((2, 13)) => scalacOptions213 + case Some((2, 12)) => scalacOptions212((plugin / Compile / packageBin).value) + case Some((2, 13)) => scalacOptions213((plugin / Compile / packageBin).value) + case Some((3, _)) => scalacOptions3 + case _ => Nil + }), + libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, _)) => scalaMacroDependencies.value case _ => Nil }), @@ -112,7 +125,7 @@ lazy val commonSettings = Seq( url("https://github.com/milessabin/shapeless"), "scm:git:git@github.com:milessabin/shapeless.git" )) -) ++ crossVersionSharedSources ++ scalaMacroDependencies +) ++ crossVersionSharedSources def configureJUnit(crossProject: CrossProject) = { crossProject @@ -162,7 +175,7 @@ lazy val plugin = project.in(file("plugin")) crossScalaVersions := Seq(Scala213, Scala212) ) -lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossType(CrossTypeMixed) +lazy val core = crossProject(JSPlatform, JVMPlatform/* TODO, NativePlatform*/).crossType(CrossTypeMixed) .configureCross(configureJUnit) .settings(moduleName := "shapeless") .settings(coreSettings:_*) @@ -173,6 +186,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossType( .settings(mimaSettings:_*) .jsSettings(commonJsSettings:_*) .jvmSettings(commonJvmSettings:_*) + /* TODO .nativeSettings( // disable scaladoc generation on native // currently getting errors like @@ -182,12 +196,13 @@ lazy val core = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossType( Compile / doc / sources := Nil, Test / sources := Nil ) + */ lazy val coreJVM = core.jvm lazy val coreJS = core.js -lazy val coreNative = core.native +//TODO lazy val coreNative = core.native -lazy val scratch = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossType(CrossTypeMixed) +lazy val scratch = crossProject(JSPlatform, JVMPlatform/* TODO, NativePlatform*/).crossType(CrossTypeMixed) .configureCross(configureJUnit) .dependsOn(core) .settings(moduleName := "scratch") @@ -198,7 +213,7 @@ lazy val scratch = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossTy lazy val scratchJVM = scratch.jvm lazy val scratchJS = scratch.js -lazy val scratchNative = scratch.native +//TODO lazy val scratchNative = scratch.native lazy val runAll = TaskKey[Unit]("runAll") @@ -212,7 +227,7 @@ def runAllIn(config: Configuration): Setting[Task[Unit]] = { } } -lazy val examples = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossType(CrossTypeMixed) +lazy val examples = crossProject(JSPlatform, JVMPlatform/* TODO, NativePlatform*/).crossType(CrossTypeMixed) .configureCross(configureJUnit) .dependsOn(core) .settings(moduleName := "examples") @@ -222,15 +237,20 @@ lazy val examples = crossProject(JSPlatform, JVMPlatform, NativePlatform).crossT .settings(noPublishSettings:_*) .jsSettings(commonJsSettings:_*) .jvmSettings(commonJvmSettings:_*) + /* + TODO .nativeSettings( Compile / sources ~= (_.filterNot(_.getName == "sexp.scala")), Test / sources := Nil ) + */ lazy val examplesJVM = examples.jvm lazy val examplesJS = examples.js -lazy val examplesNative = examples.native +//TODO lazy val examplesNative = examples.native +/* +TODO lazy val nativeTest = project .enablePlugins(ScalaNativePlugin) .settings( @@ -259,22 +279,27 @@ lazy val nativeTest = project ).dependsOn( examplesNative ) +*/ -lazy val scalaMacroDependencies: Seq[Setting[_]] = Seq( - libraryDependencies ++= Seq( +lazy val scalaMacroDependencies: Def.Initialize[Seq[ModuleID]] = Def.setting { + Seq( scalaOrganization.value % "scala-reflect" % scalaVersion.value % "provided", scalaOrganization.value % "scala-compiler" % scalaVersion.value % "provided" ) -) +} lazy val crossVersionSharedSources: Seq[Setting[_]] = Seq(Compile, Test).map { sc => (sc / unmanagedSourceDirectories) ++= { (sc / unmanagedSourceDirectories).value.flatMap { dir: File => + //Seems like cross projects don't get this source folder as well TODO: Make an issue for it + val scala2Folder = new File(dir.getPath + "-2") + if (dir.getName != "scala") Seq(dir) else CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, y)) if y >= 13 => Seq(new File(dir.getPath + "_2.13+")) - case Some((2, y)) if y < 13 => Seq(new File(dir.getPath + "_2.13-")) + case Some((2, y)) if y >= 13 => Seq(new File(dir.getPath + "_2.13+"), scala2Folder) + case Some((2, y)) if y < 13 => Seq(new File(dir.getPath + "_2.13-"), scala2Folder) + case _ => Seq(dir) } } } @@ -308,7 +333,7 @@ def buildInfoSetup(crossProject: CrossProject): CrossProject = { buildInfoKeys := Seq[BuildInfoKey](version, scalaVersion, gitHeadCommit), buildInfoOptions += BuildInfoOption.BuildTime ) - crossProject jvmConfigure transform jsConfigure transform nativeConfigure transform + crossProject jvmConfigure transform jsConfigure transform /*TODO nativeConfigure transform*/ } lazy val coreOsgiSettings = osgiSettings ++ Seq( diff --git a/core/src/main/scala-2/shapeless/CachedImplicitMacros.scala b/core/src/main/scala-2/shapeless/CachedImplicitMacros.scala new file mode 100644 index 000000000..8f55fab18 --- /dev/null +++ b/core/src/main/scala-2/shapeless/CachedImplicitMacros.scala @@ -0,0 +1,58 @@ +package shapeless + +import scala.reflect.macros.whitebox + +class CachedImplicitMacros(val c: whitebox.Context) { + import c.universe._ + + def cachedImplicitImpl[T](implicit tTag: WeakTypeTag[T]): Tree = { + val casted = c.asInstanceOf[reflect.macros.runtime.Context] + val typer = casted.callsiteTyper + val global: casted.universe.type = casted.universe + val analyzer: global.analyzer.type = global.analyzer + val tCtx = typer.context + val owner = tCtx.owner + if(!owner.isVal && !owner.isLazy) + c.abort(c.enclosingPosition, "cachedImplicit should only be used to initialize vals and lazy vals") + val tTpe = weakTypeOf[T] + val application = casted.macroApplication + val tpe = { + val tpe0 = + if (tTpe.typeSymbol.isParameter) owner.tpe.asInstanceOf[Type] + else tTpe + tpe0.finalResultType + } + val gTpe = tpe.asInstanceOf[global.Type] + + // Run our own custom implicit search that isn't allowed to find + // the thing we are enclosed in + val sCtx = tCtx.makeImplicit(false) + val is = new analyzer.ImplicitSearch( + tree = application, + pt = gTpe, + isView = false, + context0 = sCtx, + pos0 = c.enclosingPosition.asInstanceOf[global.Position] + ) { + override def searchImplicit( + implicitInfoss: List[List[analyzer.ImplicitInfo]], + isLocalToCallsite: Boolean + ): analyzer.SearchResult = { + val filteredInput = implicitInfoss.map { infos => + infos.filter { info => + val sym = if(info.sym.isLazy) info.sym else info.sym.accessedOrSelf + sym.owner != owner.owner || (!sym.isVal && !sym.isLazy) + } + } + super.searchImplicit(filteredInput, isLocalToCallsite) + } + } + val best = is.bestImplicit + if (best.isFailure) { + val errorMsg = implicitNotFoundMessage(c)(tpe) + c.abort(c.enclosingPosition, errorMsg) + } else { + best.tree.asInstanceOf[Tree] + } + } +} diff --git a/core/src/main/scala/shapeless/MacroState.scala b/core/src/main/scala-2/shapeless/MacroState.scala similarity index 100% rename from core/src/main/scala/shapeless/MacroState.scala rename to core/src/main/scala-2/shapeless/MacroState.scala diff --git a/core/src/main/scala-2/shapeless/annotation.scala b/core/src/main/scala-2/shapeless/annotation.scala new file mode 100644 index 000000000..ad39412d0 --- /dev/null +++ b/core/src/main/scala-2/shapeless/annotation.scala @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2015-9 Alexandre Archambault + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait AnnotationScalaCompat { + implicit def materialize[A, T]: Annotation[A, T] = macro AnnotationMacros.materializeAnnotationRequired[A, T] + implicit def materializeOption[A, T]: Annotation[Option[A], T] = macro AnnotationMacros.materializeAnnotationOptional[A, T] +} + +trait AnnotationsScalaCompat { + implicit def materialize[A, T, Out <: HList]: Annotations.Aux[A, T, Out] = macro AnnotationMacros.materializeVariableAnnotations[A, T, Out] +} + +trait TypeAnnotationsScalaCompat { + implicit def materialize[A, T, Out <: HList]: TypeAnnotations.Aux[A, T, Out] = macro AnnotationMacros.materializeTypeAnnotations[A, T, Out] +} + +trait AllAnnotationsScalaCompat { + implicit def materialize[T, Out <: HList]: AllAnnotations.Aux[T, Out] = macro AnnotationMacros.materializeAllVariableAnnotations[T, Out] +} + +trait AllTypeAnnotationsScalaCompat { + implicit def materialize[T, Out <: HList]: AllTypeAnnotations.Aux[T, Out] = macro AnnotationMacros.materializeAllTypeAnnotations[T, Out] +} + +class AnnotationMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def optionTpe: Type = typeOf[Option[_]].typeConstructor + def someTpe: Type = typeOf[Some[_]].typeConstructor + def noneTpe: Type = typeOf[None.type] + + /** + * FIXME Most of the content of this method is cut-n-pasted from generic.scala + * + * @return The AST of the `tpe` constructor. + */ + def construct(tpe: Type): List[Tree] => Tree = { + // FIXME Cut-n-pasted from generic.scala + val sym = tpe.typeSymbol + val isCaseClass = sym.asClass.isCaseClass + def hasNonGenericCompanionMember(name: String): Boolean = { + val mSym = sym.companion.typeSignature.member(TermName(name)) + mSym != NoSymbol && !isNonGeneric(mSym) + } + + if(isCaseClass || hasNonGenericCompanionMember("apply")) + args => q"${companionRef(tpe)}(..$args)" + else + args => q"new $tpe(..$args)" + } + + def materializeAnnotation[A: WeakTypeTag, T: WeakTypeTag]: Option[Tree] = { + val annTpe = weakTypeOf[A] + + if (!isProduct(annTpe)) + abort(s"$annTpe is not a case class-like type") + + val construct0 = construct(annTpe) + + val tpe = weakTypeOf[T] + + tpe.typeSymbol.annotations.collectFirst { + case ann if ann.tree.tpe =:= annTpe => construct0(ann.tree.children.tail) + } + } + + def materializeAnnotationRequired[A: WeakTypeTag, T: WeakTypeTag]: Tree = { + val annTpe = weakTypeOf[A] + val tpe = weakTypeOf[T] + + materializeAnnotation[A, T] match { + case Some(annTree) => + q"_root_.shapeless.Annotation.mkAnnotation[$annTpe, $tpe]($annTree)" + case None => + abort(s"No $annTpe annotation found on $tpe") + } + } + + def materializeAnnotationOptional[A: WeakTypeTag, T: WeakTypeTag]: Tree = { + val optAnnTpe = appliedType(optionTpe, weakTypeOf[A]) + val tpe = weakTypeOf[T] + + materializeAnnotation[A, T] match { + case Some(annTree) => + q"_root_.shapeless.Annotation.mkAnnotation[$optAnnTpe, $tpe](_root_.scala.Some($annTree))" + case None => + q"_root_.shapeless.Annotation.mkAnnotation[$optAnnTpe, $tpe](_root_.scala.None)" + } + } + + def materializeVariableAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag]: Tree = + materializeAnnotations[A, T, Out](typeAnnotation = false) + + def materializeAllVariableAnnotations[T: WeakTypeTag, Out: WeakTypeTag]: Tree = + materializeAllAnnotations[T, Out](typeAnnotation = false) + + def materializeTypeAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag]: Tree = + materializeAnnotations[A, T, Out](typeAnnotation = true) + + def materializeAllTypeAnnotations[T: WeakTypeTag, Out: WeakTypeTag]: Tree = + materializeAllAnnotations[T, Out](typeAnnotation = true) + + def materializeAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag](typeAnnotation: Boolean): Tree = { + val annTpe = weakTypeOf[A] + + if (!isProduct(annTpe)) + abort(s"$annTpe is not a case class-like type") + + val tpe = weakTypeOf[T] + + val annTreeOpts = getAnnotationTreeOptions(tpe, typeAnnotation).map { list => + list.find(_._1 =:= annTpe).map(_._2) + } + + val wrapTpeTrees = annTreeOpts.map { + case Some(annTree) => appliedType(someTpe, annTpe) -> q"_root_.scala.Some($annTree)" + case None => noneTpe -> q"_root_.scala.None" + } + + val outTpe = mkHListTpe(wrapTpeTrees.map { case (aTpe, _) => aTpe }) + val outTree = wrapTpeTrees.foldRight(q"_root_.shapeless.HNil": Tree) { + case ((_, bound), acc) => pq"_root_.shapeless.::($bound, $acc)" + } + + if (typeAnnotation) q"_root_.shapeless.TypeAnnotations.mkAnnotations[$annTpe, $tpe, $outTpe]($outTree)" + else q"_root_.shapeless.Annotations.mkAnnotations[$annTpe, $tpe, $outTpe]($outTree)" + } + + def materializeAllAnnotations[T: WeakTypeTag, Out: WeakTypeTag](typeAnnotation: Boolean): Tree = { + val tpe = weakTypeOf[T] + val annTreeOpts = getAnnotationTreeOptions(tpe, typeAnnotation) + + val wrapTpeTrees = annTreeOpts.map { + case Nil => + mkHListTpe(Nil) -> q"(_root_.shapeless.HNil)" + case list => + mkHListTpe(list.map(_._1)) -> list.foldRight(q"_root_.shapeless.HNil": Tree) { + case ((_, bound), acc) => pq"_root_.shapeless.::($bound, $acc)" + } + } + + val outTpe = mkHListTpe(wrapTpeTrees.map { case (aTpe, _) => aTpe }) + val outTree = wrapTpeTrees.foldRight(q"_root_.shapeless.HNil": Tree) { + case ((_, bound), acc) => + pq"_root_.shapeless.::($bound, $acc)" + } + + if (typeAnnotation) q"_root_.shapeless.AllTypeAnnotations.mkAnnotations[$tpe, $outTpe]($outTree)" + else q"_root_.shapeless.AllAnnotations.mkAnnotations[$tpe, $outTpe]($outTree)" + } + + def getAnnotationTreeOptions(tpe: Type, typeAnnotation: Boolean): List[List[(Type, Tree)]] = { + if (isProduct(tpe)) { + val constructorSyms = tpe + .member(termNames.CONSTRUCTOR) + .asMethod + .paramLists + .flatten + .map(sym => nameAsString(sym.name) -> sym) + .toMap + + fieldsOf(tpe).map { + case (name, _) => + extract(typeAnnotation, constructorSyms(nameAsString(name))).collect { + case ann if isProduct(ann.tree.tpe) => + val construct1 = construct(ann.tree.tpe) + (ann.tree.tpe, construct1(ann.tree.children.tail)) + } + } + } else if (isCoproduct(tpe)) { + ctorsOf(tpe).map { cTpe => + extract(typeAnnotation, cTpe.typeSymbol).collect { + case ann if isProduct(ann.tree.tpe) => + val construct1 = construct(ann.tree.tpe) + (ann.tree.tpe, construct1(ann.tree.children.tail)) + } + } + } else { + abort(s"$tpe is not case class like or the root of a sealed family of types") + } + } + + def extract(tpe: Boolean, s: Symbol): List[c.universe.Annotation] = { + def fromType(t: Type): List[c.universe.Annotation] = t match { + case AnnotatedType(annotations, _) => annotations.reverse + case ClassInfoType(parents, _, _) => parents.flatMap(fromType) + case TypeRef(_, sym, _) if sym.asType.isAliasType => extract(tpe, sym) + case _ => Nil + } + + if (tpe) fromType(s.typeSignature) + else s.annotations + } + +} diff --git a/core/src/main/scala-2/shapeless/coproduct.scala b/core/src/main/scala-2/shapeless/coproduct.scala new file mode 100644 index 000000000..ba321fcdf --- /dev/null +++ b/core/src/main/scala-2/shapeless/coproduct.scala @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013-14 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros + +trait CoproductScalaCompat { + + /** + * Allows to specify a `Coproduct` type with a syntax similar to `Record` and `Union`, as follows, + * + * {{{ + * type ISB = Coproduct.`Int, String, Boolean`.T + * }}} + * + * Literal types are allowed, so that the following is valid, + * + * {{{ + * type ABC = Coproduct.`'a, 'b, 'c`.T + * type TwoTrueStr = Coproduct.`2, true, "str"`.T + * }}} + */ + def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.coproductType +} diff --git a/core/src/main/scala-2/shapeless/default.scala b/core/src/main/scala-2/shapeless/default.scala new file mode 100644 index 000000000..83953c201 --- /dev/null +++ b/core/src/main/scala-2/shapeless/default.scala @@ -0,0 +1,87 @@ +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait DefaultScalaCompat { + implicit def materialize[T, L <: HList]: Default.Aux[T, L] = macro DefaultMacros.materialize[T, L] +} + +class DefaultMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def someTpe = typeOf[Some[_]].typeConstructor + def noneTpe = typeOf[None.type] + + def materialize[T: WeakTypeTag, L: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T] + val cls = classSym(tpe) + + lazy val companion = companionRef(tpe) + def altCompanion = companion.symbol.info + + val none = q"_root_.scala.None" + def some(value: Tree) = q"_root_.scala.Some($value)" + + // Symbol.alternatives is missing in Scala 2.10 + def overloadsOf(sym: Symbol) = + if (sym.isTerm) sym.asTerm.alternatives + else if (sym.isType) sym :: Nil + else Nil + + def hasDefaultParams(method: MethodSymbol) = + method.paramLists.flatten.exists(_.asTerm.isParamWithDefault) + + // The existence of multiple apply overloads with default values gets checked + // after the macro runs. Their existence can make the macro expansion fail, + // as multiple overloads can define the functions we look for below, possibly + // with wrong types, making the compilation fail with the wrong error. + // We do this check here to detect that beforehand. + def overloadsWithDefaultParamsIn(tpe: Type) = + overloadsOf(tpe.member(TermName("apply"))).count { + alt => alt.isMethod && hasDefaultParams(alt.asMethod) + } + + def defaultsFor(fields: List[(TermName, Type)]) = for { + ((_, argTpe), i) <- fields.zipWithIndex + default = tpe.companion.member(TermName(s"apply$$default$$${i + 1}")) orElse + altCompanion.member(TermName(s"$$lessinit$$greater$$default$$${i + 1}")) + } yield if (default.isTerm) { + val defaultTpe = appliedType(someTpe, devarargify(argTpe)) + val defaultVal = some(q"$companion.$default") + (defaultTpe, defaultVal) + } else (noneTpe, none) + + def mkDefault(defaults: List[(Type, Tree)]) = { + val (types, values) = defaults.unzip + val outTpe = mkHListTpe(types) + val outVal = mkHListValue(values) + q"_root_.shapeless.Default.mkDefaultByName[$tpe, $outTpe]($outVal)" + } + + if (isCaseObjectLike(cls)) return mkDefault(Nil) + if (!isCaseClassLike(cls)) abort(s"$tpe is not a case class or case class like") + + // ClassSymbol.primaryConstructor is missing in Scala 2.10 + val primaryCtor = overloadsOf(tpe.decl(termNames.CONSTRUCTOR)).find { + alt => alt.isMethod && alt.asMethod.isPrimaryConstructor + }.getOrElse { + c.abort(c.enclosingPosition, s"Cannot get primary constructor of $tpe") + }.asMethod + + // Checking if the primary constructor has default parameters, and returning + // a Default instance with non-empty types / values only if that holds. + // The apply$default$... methods below may still exist without these, if an additional + // apply method has default parameters. We want to ignore them in this case. + val hasUniqueDefaults = hasDefaultParams(primaryCtor) && { + val k = overloadsWithDefaultParamsIn(tpe.companion) + k == 1 || (k == 0 && overloadsWithDefaultParamsIn(altCompanion) == 1) + } + + mkDefault { + val fields = fieldsOf(tpe) + if (hasUniqueDefaults) defaultsFor(fields) + else List.fill(fields.size)((noneTpe, none)) + } + } +} diff --git a/core/src/main/scala-2/shapeless/generic.scala b/core/src/main/scala-2/shapeless/generic.scala new file mode 100644 index 000000000..e54fb98e3 --- /dev/null +++ b/core/src/main/scala-2/shapeless/generic.scala @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2012-18 Lars Hupel, Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.annotation.tailrec +import scala.language.experimental.macros +import scala.reflect.macros.{blackbox, whitebox} + +trait GenericScalaCompat { + + implicit def materialize[T, R]: Generic.Aux[T, R] = macro GenericMacros.materialize[T, R] +} + +trait LabelledGenericScalaCompat { + + implicit def materialize[T, R]: LabelledGeneric.Aux[T, R] = + macro LabelledMacros.mkLabelledGeneric[T, R] +} + +trait IsTupleScalaCompat { + implicit def apply[T]: IsTuple[T] = macro GenericMacros.mkIsTuple[T] +} + +trait HasProductGenericScalaCompat { + implicit def apply[T]: HasProductGeneric[T] = macro GenericMacros.mkHasProductGeneric[T] +} + +trait HasCoproductGenericScalaCompat { + implicit def apply[T]: HasCoproductGeneric[T] = macro GenericMacros.mkHasCoproductGeneric[T] +} + +trait ReprTypes { + val c: blackbox.Context + import c.universe.{Symbol => _, _} + + def hlistTpe = typeOf[HList] + def hnilTpe = typeOf[HNil] + def hconsTpe = typeOf[::[_, _]].typeConstructor + def coproductTpe = typeOf[Coproduct] + def cnilTpe = typeOf[CNil] + def cconsTpe = typeOf[:+:[_, _]].typeConstructor + + def atatTpe = typeOf[tag.@@[_,_]].typeConstructor + def fieldTypeTpe = typeOf[shapeless.labelled.FieldType[_, _]].typeConstructor + def keyTagTpe = typeOf[shapeless.labelled.KeyTag[_, _]].typeConstructor + def symbolTpe = typeOf[Symbol] + + def objectRef[O: TypeTag]: Tree = Ident(typeOf[O].termSymbol) +} + +trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { + val c: blackbox.Context + + import c.universe._ + + def abort(msg: String): Nothing = + c.abort(c.enclosingPosition, msg) + + def isReprType(tpe: Type): Boolean = + tpe <:< hlistTpe || tpe <:< coproductTpe + + def isReprType1(tpe: Type): Boolean = + isReprType(lowerKind(tpe)) + + /** + * Lower the order of `tpe`'s kind by applying `Any` in place of all type parameters (`Any` is poly-kinded). + * Note that the resulting type is dealiased before being returned. + * + * {{{ + * lowerKind(typeOf[List[_]].typeConstructor) -> List[Any] + * }}} + */ + def lowerKind(tpe: Type): Type = + appliedType(tpe, tpe.typeParams.map(_ => definitions.AnyTpe)).dealias + + def isProductAux(tpe: Type): Boolean = + tpe.typeSymbol.isClass && { + val cls = classSym(tpe) + isCaseObjectLike(cls) || isCaseClassLike(cls) || HasApplyUnapply(tpe) || HasCtorUnapply(tpe) + } + + def isProduct(tpe: Type): Boolean = + tpe =:= definitions.UnitTpe || (!(tpe =:= definitions.AnyRefTpe) && isProductAux(tpe)) + + def isProduct1(tpe: Type): Boolean = + isProduct(lowerKind(tpe)) + + def isCoproduct(tpe: Type): Boolean = + tpe.typeSymbol.isClass && { + val cls = classSym(tpe) + (cls.isTrait || cls.isAbstract) && cls.isSealed + } + + def ownerChain(sym: Symbol): List[Symbol] = { + @tailrec + def loop(sym: Symbol, acc: List[Symbol]): List[Symbol] = + if(sym.owner == NoSymbol) acc + else loop(sym.owner, sym :: acc) + + loop(sym, Nil) + } + + def isAnonOrRefinement(sym: Symbol): Boolean = { + val nameStr = sym.name.toString + nameStr.contains("$anon") || nameStr == "" + } + + /** + * @return a List of name and type pairs for the fields of type `tpe`. + * @see [[isCaseAccessorLike]] for the definition of what is considered a field. + * */ + def fieldsOf(tpe: Type): List[(TermName, Type)] = { + val clazz = tpe.typeSymbol.asClass + val isCaseClass = clazz.isCaseClass + if (isCaseObjectLike(clazz) || isAnonOrRefinement(clazz)) Nil + else tpe.decls.sorted.collect { + case sym: TermSymbol if isCaseAccessorLike(sym, isCaseClass) => + (sym.name, sym.typeSignatureIn(tpe).finalResultType) + } + } + + def productCtorsOf(tpe: Type): List[Symbol] = tpe.decls.toList.filter(_.isConstructor) + + def accessiblePrimaryCtorOf(tpe: Type): Option[Symbol] = { + for { + ctor <- tpe.decls.find { sym => sym.isMethod && sym.asMethod.isPrimaryConstructor && isAccessible(tpe, sym) } + if !ctor.isJava || productCtorsOf(tpe).size == 1 + } yield ctor + } + + def ctorsOf(tpe: Type): List[Type] = distinctCtorsOfAux(tpe, hk = false) + def ctorsOf1(tpe: Type): List[Type] = distinctCtorsOfAux(tpe, hk = true) + + def distinctCtorsOfAux(tpe: Type, hk: Boolean): List[Type] = { + def distinct[A](list: List[A])(eq: (A, A) => Boolean): List[A] = list.foldLeft(List.empty[A]) { (acc, x) => + if (!acc.exists(eq(x, _))) x :: acc + else acc + }.reverse + distinct(ctorsOfAux(tpe, hk))(_ =:= _) + } + + def ctorsOfAux(tpe: Type, hk: Boolean): List[Type] = { + def collectCtors(classSym: ClassSymbol): List[ClassSymbol] = { + classSym.knownDirectSubclasses.toList flatMap { child0 => + val child = child0.asClass + child.typeSignature // Workaround for + if (isCaseClassLike(child) || isCaseObjectLike(child)) + List(child) + else if (child.isSealed) + collectCtors(child) + else + abort(s"$child is not case class like or a sealed trait") + } + } + + if(isProduct(tpe)) + List(tpe) + else if(isCoproduct(tpe)) { + val basePre = prefix(tpe) + val baseSym = classSym(tpe) + val baseTpe = + if(!hk) tpe + else { + val tc = tpe.typeConstructor + val paramSym = tc.typeParams.head + val paramTpe = paramSym.asType.toType + appliedType(tc, paramTpe) + } + val baseArgs = baseTpe.dealias.typeArgs + + def isLess(sym1: Symbol, sym2: Symbol): Boolean = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gSym1 = sym1.asInstanceOf[global.Symbol] + val gSym2 = sym2.asInstanceOf[global.Symbol] + gSym1.isLess(gSym2) + } + + def orderSyms(s1: Symbol, s2: Symbol): Boolean = { + val fn1 = s1.fullName + val fn2 = s2.fullName + fn1 < fn2 || (fn1 == fn2 && isLess(s1, s2)) + } + + val ctors = collectCtors(baseSym).sortWith(orderSyms).flatMap { sym => + import c.internal._ + + val owner = sym.owner + val isNamed = !isAnonOrRefinement(sym) + + // Construct a stable prefix from the path. + val pre = if (sym.isStatic) prefix(sym.toType) else { + // Look for a path from the macro call site to the subtype. + val owners = ownerChain(if (isNamed) owner else owner.owner) + val prePaths = for (pre <- Iterator.iterate(basePre)(prefix).takeWhile(_ != NoPrefix)) + yield (pre, owners.iterator.dropWhile(pre.baseType(_) == NoType)) + + // Find a path from a (sub-)prefix or the enclosing owner. + val (pre0, path) = prePaths.find(_._2.nonEmpty).getOrElse { + val enclosing = ownerChain(enclosingOwner) + val common = owners zip enclosing indexWhere { case (o1, o2) => o1 != o2 } + (NoPrefix, if (common < 0) Iterator.empty else owners.iterator drop common - 1) + } + + path.drop(1).foldLeft(pre0) { (pre1, part) => + if (part.isType) part.asType.toTypeIn(pre1) + else abort(s"$tpe has a subtype $sym with unstable prefix") + } + } + + val ctor = if (isNamed) { + if (sym.isModuleClass) { + singleType(pre, sym.module) + } else { + val subst = thisType(sym).baseType(baseSym).typeArgs.map(_.typeSymbol) + val params = sym.typeParams + val free = params.exists(!subst.contains(_)) + val args = for (param <- params) yield { + val i = subst.indexOf(param) + if (i >= 0) baseArgs(i) else param.asType.toType + } + + val ref = typeRef(pre, sym, args) + if (free) existentialAbstraction(params, ref) else ref + } + } else { + def ownerIsSubType = owner.typeSignatureIn(pre) <:< baseTpe + if (owner.isTerm && owner.asTerm.isVal && ownerIsSubType) singleType(pre, owner) + else abort(s"$tpe has a subtype $sym with unstable prefix") + } + + if (!isAccessible(ctor)) abort(s"$tpe has an inaccessible subtype $ctor") + else if (ctor <:< baseTpe) Some(ctor) + else None + } + + if (ctors.isEmpty) abort(s"Sealed trait $tpe has no case class subtypes") + else ctors + } else { + abort(s"$tpe is not a case class, case class-like, a sealed trait or Unit") + } + } + + def nameAsString(name: Name): String = + name.decodedName.toString.trim + + def nameAsValue(name: Name): Constant = + Constant(nameAsString(name)) + + def nameOf(tpe: Type): Name = + tpe.typeSymbol.name + + def mkHListValue(elems: List[Tree]): Tree = + elems.foldRight(q"_root_.shapeless.HNil": Tree) { + case (elem, acc) => q"_root_.shapeless.::($elem, $acc)" + } + + /** + * Fold `items` into a type using `cons` as a type constructor. + * + * {{{ + * mkCompoundTpe(hnilTpe, hconsTpe, Seq(typeOf[String], typeOf[Int])) -> String :: Int :: HNil + * }}} + */ + def mkCompoundTpe(nil: Type, cons: Type, items: Seq[Type]): Type = + items.foldRight(nil) { (tpe, acc) => + appliedType(cons, List(devarargify(tpe), acc)) + } + + /** + * Convert `items` to corresponding HList type. + */ + def mkHListTpe(items: Seq[Type]): Type = + mkCompoundTpe(hnilTpe, hconsTpe, items) + + /** + * Convert `items` to corresponding Coproduct type. + */ + def mkCoproductTpe(items: Seq[Type]): Type = + mkCompoundTpe(cnilTpe, cconsTpe, items) + + def unpackHList(tpe: Type): Vector[Type] = + unpackReprType(tpe, hnilTpe, hconsTpe) + + def unpackCoproduct(tpe: Type): Vector[Type] = + unpackReprType(tpe, cnilTpe, cconsTpe) + + def unpackReprType(tpe: Type, nil: Type, cons: Type): Vector[Type] = { + val consSym = cons.typeSymbol + @tailrec def unpack(tpe: Type, acc: Vector[Type]): Vector[Type] = + if (tpe <:< nil) acc else tpe.baseType(consSym) match { + case TypeRef(_, _, List(head, tail)) => unpack(tail, acc :+ head) + case _ => abort(s"$tpe is not an HList or Coproduct type") + } + + unpack(tpe, Vector.empty) + } + + object FieldType { + import internal._ + + private val KeyTagSym = keyTagTpe.typeSymbol + + def apply(key: Type, value: Type): Type = + appliedType(fieldTypeTpe, key, value) + + def unapply(field: Type): Option[(Type, Type)] = field.dealias match { + case RefinedType(List(value, TypeRef(_, KeyTagSym, List(key, _))), scope) + if scope.isEmpty => Some(key -> value) + case RefinedType(parents :+ TypeRef(_, KeyTagSym, List(key, value)), scope) + if value =:= refinedType(parents, scope) => Some(key -> value) + case _ => + None + } + } + + def findField(record: Type, key: Type): Option[(Type, Type, Int)] = + findField(unpackHList(record), key) + + def findField(fields: Seq[Type], key: Type): Option[(Type, Type, Int)] = + fields.iterator.zipWithIndex.collectFirst { + case (FieldType(k, v), i) if k =:= key => (k, v, i) + } + + def appliedTypTree1(tpe: Type, param: Type, arg: TypeName): Tree = { + tpe match { + case t if t =:= param => + Ident(arg) + case PolyType(params, body) if params.head.asType.toType =:= param => + appliedTypTree1(body, param, arg) + case TypeRef(pre, sym, Nil) => + mkAttributedRef(pre, sym) + case TypeRef(pre, sym, args) => + val argTrees = args.map(appliedTypTree1(_, param, arg)) + AppliedTypeTree(mkAttributedRef(pre, sym), argTrees) + case other => + tq"$other" + } + } + + def mkCompoundTypTree1(nil: Type, cons: Type, items: List[Type], param: Type, arg: TypeName): Tree = + items.foldRight(mkAttributedRef(nil): Tree) { case (tpe, acc) => + AppliedTypeTree(mkAttributedRef(cons), List(appliedTypTree1(tpe, param, arg), acc)) + } + + def mkHListTypTree1(items: List[Type], param: Type, arg: TypeName): Tree = + mkCompoundTypTree1(hnilTpe, hconsTpe, items, param, arg) + + def mkCoproductTypTree1(items: List[Type], param: Type, arg: TypeName): Tree = + mkCompoundTypTree1(cnilTpe, cconsTpe, items, param, arg) + + def param1(tpe: Type): Type = + tpe match { + case t if tpe.takesTypeArgs => t.typeParams.head.asType.toType + case TypeRef(_, _, List(arg)) => arg + case _ => NoType + } + + def reprTypTree1(tpe: Type, arg: TypeName): Tree = { + val param = param1(tpe) + if(isProduct1(tpe)) mkHListTypTree1(fieldsOf(tpe).map(_._2), param, arg) + else mkCoproductTypTree1(ctorsOf1(tpe), param, arg) + } + + def isCaseClassLike(sym: ClassSymbol): Boolean = { + def isConcrete = !(sym.isAbstract || sym.isTrait || sym == symbolOf[Object]) + def isFinalLike = sym.isFinal || sym.knownDirectSubclasses.isEmpty + def ctor = for { + ctor <- accessiblePrimaryCtorOf(sym.typeSignature) + Seq(params) <- Option(ctor.typeSignature.paramLists) + if params.size == fieldsOf(sym.typeSignature).size + } yield ctor + sym.isCaseClass || (isConcrete && isFinalLike && ctor.isDefined) + } + + def isCaseObjectLike(sym: ClassSymbol): Boolean = sym.isModuleClass + + def isCaseAccessorLike(sym: TermSymbol, inCaseClass: Boolean): Boolean = { + val isGetter = + if (inCaseClass) sym.isCaseAccessor && !sym.isMethod + else sym.isGetter && sym.isPublic && (sym.isParamAccessor || sym.isLazy) + isGetter && !isNonGeneric(sym) + } + + def classSym(tpe: Type): ClassSymbol = { + val sym = tpe.typeSymbol + if (!sym.isClass) + abort(s"$sym is not a class or trait") + + val classSym = sym.asClass + classSym.typeSignature // Workaround for + + classSym + } + + // See https://github.com/milessabin/shapeless/issues/212 + def companionRef(tpe: Type): Tree = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gTpe = tpe.asInstanceOf[global.Type] + val pre = gTpe.prefix + val cSym = patchedCompanionSymbolOf(tpe.typeSymbol).asInstanceOf[global.Symbol] + if(cSym != NoSymbol) + global.gen.mkAttributedRef(pre, cSym).asInstanceOf[Tree] + else + Ident(tpe.typeSymbol.name.toTermName) // Attempt to refer to local companion + } + + def isAccessible(pre: Type, sym: Symbol): Boolean = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val typer = c.asInstanceOf[scala.reflect.macros.runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer] + val typerContext = typer.context + typerContext.isAccessible( + sym.asInstanceOf[global.Symbol], + pre.asInstanceOf[global.Type] + ) + } + def isAccessible(tpe: Type): Boolean = + isAccessible(prefix(tpe), tpe.typeSymbol) + + // 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: Symbol): 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 prefix(tpe: Type): Type = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gTpe = tpe.asInstanceOf[global.Type] + gTpe.prefix.asInstanceOf[Type] + } + + def mkAttributedRef(tpe: Type): Tree = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gTpe = tpe.asInstanceOf[global.Type] + val pre = gTpe.prefix + val sym = gTpe.typeSymbol + global.gen.mkAttributedRef(pre, sym).asInstanceOf[Tree] + } + + def mkAttributedRef(pre: Type, sym: Symbol): Tree = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gPre = pre.asInstanceOf[global.Type] + val gSym = sym.asInstanceOf[global.Symbol] + global.gen.mkAttributedRef(gPre, gSym).asInstanceOf[Tree] + } + + def mkAttributedRef(singleton: SingleType): Tree = { + val SingleType(pre, sym) = (singleton: @unchecked) + val getter = sym.asTerm.getter.orElse(sym) + mkAttributedRef(pre, getter) + } + + /** + * Check if `sym` or any of its overrides are annotated by [[nonGeneric]]. + */ + def isNonGeneric(sym: Symbol): Boolean = { + def check(sym: Symbol): Boolean = { + // See https://issues.scala-lang.org/browse/SI-7424 + sym.typeSignature // force loading method's signature + sym.annotations.foreach(_.tree.tpe) // force loading all the annotations + + sym.annotations.exists(_.tree.tpe =:= typeOf[nonGeneric]) + } + + // See https://issues.scala-lang.org/browse/SI-7561 + check(sym) || + (sym.isTerm && sym.asTerm.isAccessor && check(sym.asTerm.accessed)) || + sym.overrides.exists(isNonGeneric) + } + + def isTuple(tpe: Type): Boolean = + tpe <:< typeOf[Unit] || definitions.TupleClass.seq.contains(tpe.typeSymbol) + + def isVararg(tpe: Type): Boolean = + tpe.typeSymbol == c.universe.definitions.RepeatedParamClass + + /** + * Convert a varargs type to corresponding Seq type. + * + * {{{ + * String* -> Seq[String] + * }}} + */ + def devarargify(tpe: Type): Type = + tpe match { + case TypeRef(_, _, args) if isVararg(tpe) => + appliedType(varargTC, args) + case _ => tpe + } + + def unByName(tpe: Type): Type = + tpe match { + case TypeRef(_, sym, List(tpe)) if sym == definitions.ByNameParamClass => tpe + case tpe => tpe + } + + def equalTypes(as: List[Type], bs: List[Type]): Boolean = + as.length == bs.length && (as zip bs).foldLeft(true) { case (acc, (a, b)) => acc && unByName(a) =:= unByName(b) } + + def alignFields(tpe: Type, args: List[(TermName, Type)]): Option[List[(TermName, Type)]] = for { + fields <- Option(fieldsOf(tpe)) + if fields.size == args.size + if fields.zip(args).forall { case ((fn, ft), (an, at)) => + (fn == an || at.typeSymbol == definitions.ByNameParamClass) && ft =:= unByName(at) + } + } yield fields + + def numNonCaseParamLists(tpe: Type): Int = { + val companion = patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature + val apply = companion.member(TermName("apply")) + if (apply.isMethod && !isNonGeneric(apply) && isAccessible(companion, apply)) { + val paramLists = apply.typeSignatureIn(companion).paramLists + val numParamLists = paramLists.length + if (numParamLists <= 1) 0 + else { + if (paramLists.last.headOption.exists(_.isImplicit)) + numParamLists-2 + else + numParamLists-1 + } + } else 0 + } + + object HasApply { + def unapply(tpe: Type): Option[List[(TermName, Type)]] = for { + companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature) + apply = companion.member(TermName("apply")) + if apply.isMethod && !isNonGeneric(apply) + if isAccessible(companion, apply) + Seq(params) <- Option(apply.typeSignatureIn(companion).paramLists) + aligned <- alignFields(tpe, for (param <- params) + yield param.name.toTermName -> param.typeSignature) + } yield aligned + } + + object HasUnapply { + def unapply(tpe: Type): Option[List[Type]] = for { + companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature) + unapply = companion.member(TermName("unapply")) + if unapply.isMethod && !isNonGeneric(unapply) + if isAccessible(companion, unapply) + returnTpe <- unapply.asMethod.typeSignatureIn(companion).finalResultType + .baseType(symbolOf[Option[_]]).typeArgs.headOption + } yield if (returnTpe <:< typeOf[Product]) returnTpe.typeArgs else List(returnTpe) + } + + object HasUniqueCtor { + def unapply(tpe: Type): Option[List[(TermName, Type)]] = for { + ctor <- accessiblePrimaryCtorOf(tpe) + if !isNonGeneric(ctor) + Seq(params) <- Option(ctor.typeSignatureIn(tpe).paramLists) + aligned <- alignFields(tpe, for (param <- params) + yield param.name.toTermName -> param.typeSignature) + } yield aligned + } + + object HasApplyUnapply { + def apply(tpe: Type): Boolean = unapply(tpe).isDefined + def unapply(tpe: Type): Option[List[(TermName, Type)]] = + (tpe, tpe) match { + case (HasApply(as), HasUnapply(bs)) if equalTypes(as.map(_._2), bs) => Some(as) + case _ => None + } + } + + object HasCtorUnapply { + def apply(tpe: Type): Boolean = unapply(tpe).isDefined + def unapply(tpe: Type): Option[List[(TermName, Type)]] = + (tpe, tpe) match { + case(HasUniqueCtor(as), HasUnapply(bs)) if equalTypes(as.map(_._2), bs) => Some(as) + case _ => None + } + } + + trait CtorDtor { + def construct(args: List[Tree]): Tree + def binding: (Tree, List[Tree]) + def reprBinding: (Tree, List[Tree]) + } + + object CtorDtor { + def apply(tpe: Type): CtorDtor = { + val sym = tpe.typeSymbol + val isCaseClass = sym.asClass.isCaseClass + + val repWCard = Star(Ident(termNames.WILDCARD)) // like pq"_*" except that it does work + + def narrow(tree: Tree, tpe: Type): Tree = + tpe match { + case ConstantType(c) => + q"$c.asInstanceOf[$tpe]" + case _ => + tree + } + + def narrow1(tree: Tree, tpe: Type): Tree = + if(isVararg(tpe)) + q"$tree: _*" + else + narrow(tree, tpe) + + def mkCtorDtor0(elems0: List[(TermName, Type)]) = { + val elems = elems0.map { case (_, tpe) => (TermName(c.freshName("pat")), tpe) } + val pattern = pq"${companionRef(tpe)}(..${elems.map { case (binder, tpe) => if(isVararg(tpe)) pq"$binder @ $repWCard" else pq"$binder"}})" + val reprPattern = + elems.foldRight(q"_root_.shapeless.HNil": Tree) { + case ((bound, _), acc) => pq"_root_.shapeless.::($bound, $acc)" + } + val nonCaseParamLists: List[List[Tree]] = List.fill(numNonCaseParamLists(tpe))(Nil) + new CtorDtor { + def construct(args: List[Tree]): Tree = q"${companionRef(tpe)}(...${args :: nonCaseParamLists})" + def binding: (Tree, List[Tree]) = (pattern, elems.map { case (binder, tpe) => narrow(q"$binder", tpe) }) + def reprBinding: (Tree, List[Tree]) = (reprPattern, elems.map { case (binder, tpe) => narrow1(q"$binder", tpe) }) + } + } + + def mkCtorDtor1(elems: List[(TermName, TermName, Type)], pattern: Tree, rhs: List[Tree]) = { + val reprPattern = + elems.foldRight(q"_root_.shapeless.HNil": Tree) { + case ((bound, _, _), acc) => pq"_root_.shapeless.::($bound, $acc)" + } + new CtorDtor { + def construct(args: List[Tree]): Tree = q"new $tpe(..$args)" + def binding: (Tree, List[Tree]) = (pattern, rhs) + def reprBinding: (Tree, List[Tree]) = (reprPattern, elems.map { case (binder, _, tpe) => narrow1(q"$binder", tpe) }) + } + } + + lowerKind(tpe) match { + // case 1: Unit + case tpe if tpe =:= typeOf[Unit] => + new CtorDtor { + def construct(args: List[Tree]): Tree = q"()" + def binding: (Tree, List[Tree]) = (pq"()", Nil) + def reprBinding: (Tree, List[Tree]) = (pq"_root_.shapeless.HNil", Nil) + } + + // case 2: singleton + case tpe if isCaseObjectLike(tpe.typeSymbol.asClass) => + val singleton = + tpe match { + case SingleType(pre, sym) => + c.internal.gen.mkAttributedRef(pre, sym) + case TypeRef(pre, sym, List()) if sym.isModule => + c.internal.gen.mkAttributedRef(pre, sym.asModule) + case TypeRef(pre, sym, List()) if sym.isModuleClass => + c.internal.gen.mkAttributedRef(pre, sym.asClass.module) + case _ => + abort(s"Bad case object-like type $tpe") + } + new CtorDtor { + def construct(args: List[Tree]): Tree = q"$singleton: $tpe" + def binding: (Tree, List[Tree]) = (pq"_: $tpe", Nil) + def reprBinding: (Tree, List[Tree]) = (pq"_root_.shapeless.HNil", Nil) + } + + // case 3: case class + case tpe if isCaseClass => mkCtorDtor0(fieldsOf(tpe)) + + // case 4: exactly one matching public apply/unapply + case HasApplyUnapply(args) => mkCtorDtor0(args) + + // case 5: concrete, exactly one public constructor with matching public unapply + case HasCtorUnapply(args) => + val elems = args.map { case (name, tpe) => (TermName(c.freshName("pat")), name, tpe) } + val pattern = pq"${companionRef(tpe)}(..${elems.map { case (binder, _, tpe) => if(isVararg(tpe)) pq"$binder @ $repWCard" else pq"$binder" }})" + val rhs = elems.map { case (binder, _, tpe) => narrow(q"$binder", tpe) } + mkCtorDtor1(elems, pattern, rhs) + + // case 6: concrete, exactly one public constructor with matching accessible fields + case HasUniqueCtor(args) => + val elems = args.map { case (name, tpe) => (TermName(c.freshName("pat")), name, tpe) } + val binder = TermName(c.freshName("pat")) + val pattern = pq"$binder" + val rhs = elems.map { case (_, name, tpe) => narrow(q"$binder.$name", tpe) } + mkCtorDtor1(elems, pattern, rhs) + + case _ => abort(s"Bad product type $tpe") + } + } + } +} + +class GenericMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + private val generic = objectRef[Generic.type] + + def materialize[T: WeakTypeTag, R]: Tree = mkGeneric[T] + + def mkGeneric[T: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T] + if (isReprType(tpe)) + abort("No Generic instance available for HList or Coproduct") + + if (isProduct(tpe)) mkProductGeneric(tpe) + else mkCoproductGeneric(tpe) + } + + def mkProductGeneric(tpe: Type): Tree = { + val repr = mkHListTpe(fieldsOf(tpe).map(_._2)) + val ctorDtor = CtorDtor(tpe) + val (p, ts) = ctorDtor.binding + val to = cq"$p => ${mkHListValue(ts)}.asInstanceOf[$repr]" + val (rp, rts) = ctorDtor.reprBinding + val from = cq"$rp => ${ctorDtor.construct(rts)}.asInstanceOf[$tpe]" + q"$generic.instance[$tpe, $repr]({ case $to }, { case $from })" + } + + def mkCoproductGeneric(tpe: Type): Tree = { + def mkCoproductCases(tpe0: Type, index: Int): Tree = tpe0 match { + case TypeRef(pre, sym, Nil) if sym.isModuleClass => + cq"p if p eq ${mkAttributedRef(pre, sym.asClass.module)} => $index" + case singleton: SingleType => + cq"p if p eq ${mkAttributedRef(singleton)} => $index" + case _ => + cq"_: $tpe0 => $index" + } + + val coproduct = objectRef[Coproduct.type] + val ctors = ctorsOf(tpe) + val repr = mkCoproductTpe(ctors) + val toCases = ctors.zipWithIndex.map((mkCoproductCases _).tupled) + val to = q"$coproduct.unsafeMkCoproduct((p: @_root_.scala.unchecked) match { case ..$toCases }, p).asInstanceOf[$repr]" + q"$generic.instance[$tpe, $repr]((p: $tpe) => $to, $coproduct.unsafeGet(_).asInstanceOf[$tpe])" + } + + def mkIsTuple[T: WeakTypeTag]: Tree = { + val tTpe = weakTypeOf[T] + if (!isTuple(tTpe)) + abort(s"Unable to materialize IsTuple for non-tuple type $tTpe") + + q"new ${weakTypeOf[IsTuple[T]]}" + } + + def mkHasProductGeneric[T: WeakTypeTag]: Tree = { + val tTpe = weakTypeOf[T] + if (isReprType(tTpe) || !isProduct(tTpe)) + abort(s"Unable to materialize HasProductGeneric for $tTpe") + + q"new ${weakTypeOf[HasProductGeneric[T]]}" + } + + def mkHasCoproductGeneric[T: WeakTypeTag]: Tree = { + val tTpe = weakTypeOf[T] + if (isReprType(tTpe) || !isCoproduct(tTpe)) + abort(s"Unable to materialize HasCoproductGeneric for $tTpe") + + q"new ${weakTypeOf[HasCoproductGeneric[T]]}" + } +} diff --git a/core/src/main/scala-2/shapeless/generic1.scala b/core/src/main/scala-2/shapeless/generic1.scala new file mode 100644 index 000000000..460119d71 --- /dev/null +++ b/core/src/main/scala-2/shapeless/generic1.scala @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2015-18 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait Generic1ScalaCompat { + + implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] = + macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ] + + implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[U, t] })#λ] = + macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[U, t] })#λ] +} + +trait Generic10ScalaCompat { + implicit def apply[T[_], FR[_[_]]]: Generic1[T, FR] = macro Generic1Macros.mkGeneric1Impl[T, FR] +} + +trait IsHCons1ScalaCompat { + + implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = + macro IsHCons1Macros.mkIsHCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] + + implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = + macro IsHCons1Macros.mkIsHCons1Impl[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] + + implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = + macro IsHCons1Macros.mkIsHCons1Impl[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] + + implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = + macro IsHCons1Macros.mkIsHCons1Impl[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] +} + +trait IsHCons10ScalaCompat { + implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = macro IsHCons1Macros.mkIsHCons1Impl[L, FH, FT] +} + +trait IsCCons1ScalaCompat { + + implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = + macro IsCCons1Macros.mkIsCCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] + + implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = + macro IsCCons1Macros.mkIsCCons1Impl[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] + + implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = + macro IsCCons1Macros.mkIsCCons1Impl[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] + + implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = + macro IsCCons1Macros.mkIsCCons1Impl[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] +} + +trait IsCCons10ScalaCompat { + implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsCCons1[L, FH, FT] = macro IsCCons1Macros.mkIsCCons1Impl[L, FH, FT] +} + +trait Split1ScalaCompat { + + implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] = + macro Split1Macros.mkSplit1Impl[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] + + implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] = + macro Split1Macros.mkSplit1Impl[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] + + implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] = + macro Split1Macros.mkSplit1Impl[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] + + implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] = + macro Split1Macros.mkSplit1Impl[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] +} + +trait Split10ScalaCompat { + implicit def apply[L[_], FO[_[_]], FI[_[_]]]: Split1[L, FO, FI] = macro Split1Macros.mkSplit1Impl[L, FO, FI] +} + +class Generic1Macros(val c: whitebox.Context) extends CaseClassMacros { + import c.ImplicitCandidate + import c.universe._ + import definitions._ + + private val generic1 = objectRef[Generic1.type] + + def mkGeneric1Impl[T[_], FR[_[_]]](implicit tTag: WeakTypeTag[T[_]], frTag: WeakTypeTag[FR[Any]]): Tree = { + val tpe = tTag.tpe.etaExpand + val frTpe = c.openImplicits.headOption match { + case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, tpe)), _)) => tpe + case _ => frTag.tpe.typeConstructor + } + + if (isReprType1(tpe)) + abort("No Generic1 instance available for HList or Coproduct") + + if (isProduct1(tpe)) mkProductGeneric1(tpe, frTpe) + else mkCoproductGeneric1(tpe, frTpe) + } + + def mkProductGeneric1(tpe: Type, frTpe: Type): Tree = { + val ctorDtor = CtorDtor(tpe) + val (p, ts) = ctorDtor.binding + val to = cq"$p => ${mkHListValue(ts)}" + val (rp, rts) = ctorDtor.reprBinding + val from = cq"$rp => ${ctorDtor.construct(rts)}" + val name = TypeName(c.freshName("P")) + val reprTpt = reprTypTree1(tpe, name) + val reprName = TypeName(c.freshName("R")) + + q""" + type $reprName[$name] = $reprTpt + $generic1.unsafeInstance[$tpe, $frTpe, $reprName]({ case $to }, { case $from }) + """ + } + + def mkCoproductGeneric1(tpe: Type, frTpe: Type): Tree = { + def mkCoproductCases(tpe: Type, index: Int) = { + val pat = TermName(c.freshName("pat")) + val tc = tpe.typeConstructor + val params = tc.typeParams.map(_ => Bind(typeNames.WILDCARD, EmptyTree)) + val tpt = AppliedTypeTree(mkAttributedRef(tc), params) + cq"$pat: $tpt => $index" + } + + val name = TypeName(c.freshName("C")) + val reprTpt = reprTypTree1(tpe, name) + val reprName = TypeName(c.freshName("R")) + val coproduct = objectRef[Coproduct.type] + val toCases = ctorsOf1(tpe).zipWithIndex.map((mkCoproductCases _).tupled) + val to = q"$coproduct.unsafeMkCoproduct((ft: @_root_.scala.unchecked) match { case ..$toCases }, ft).asInstanceOf[$reprName[$AnyTpe]]" + val from = q"$coproduct.unsafeGet(rt).asInstanceOf[${appliedType(tpe, AnyTpe)}]" + + q""" + type $reprName[$name] = $reprTpt + $generic1.unsafeInstance[$tpe, $frTpe, $reprName](ft => $to, rt => $from) + """ + } +} + +class IsHCons1Macros(val c: whitebox.Context) extends IsCons1Macros { + import c.universe._ + + def mkIsHCons1Impl[L[_], FH[_[_]], FT[_[_]]] + (implicit lTag: WeakTypeTag[L[_]], fhTag: WeakTypeTag[FH[Any]], ftTag: WeakTypeTag[FT[Any]]): Tree = + mkIsCons1(lTag.tpe, fhTag.tpe.typeConstructor, ftTag.tpe.typeConstructor) + + val isCons1TC: Tree = objectRef[IsHCons1.type] + val consTpe: Type = hconsTpe + + def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) = { + val cons = objectRef[::.type] + (q"$cons(_, _)", q"{ case $cons(hd, tl) => (hd, tl) }") + } +} + +class IsCCons1Macros(val c: whitebox.Context) extends IsCons1Macros { + import c.universe._ + import definitions._ + + def mkIsCCons1Impl[L[_], FH[_[_]], FT[_[_]]] + (implicit lTag: WeakTypeTag[L[_]], fhTag: WeakTypeTag[FH[Any]], ftTag: WeakTypeTag[FT[Any]]): Tree = + mkIsCons1(lTag.tpe, fhTag.tpe.typeConstructor, ftTag.tpe.typeConstructor) + + val isCons1TC: Tree = objectRef[IsCCons1.type] + val consTpe: Type = cconsTpe + + def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) = { + val left = objectRef[Left.type] + val right = objectRef[Right.type] + val inl = objectRef[Inl.type] + val inr = objectRef[Inr.type] + + ( + q"""{ + case $left(hd) => $inl(hd: $hdName[$AnyTpe]) + case $right(tl) => $inr(tl: $tlName[$AnyTpe]) + }""", + q"""{ + case $inl(hd) => $left(hd: $hdName[$AnyTpe]) + case $inr(tl) => $right(tl: $tlName[$AnyTpe]) + }""" + ) + } +} + +trait IsCons1Macros extends CaseClassMacros { + val c: whitebox.Context + import c.ImplicitCandidate + import c.internal._ + import c.universe._ + + def isCons1TC: Tree + def consTpe: Type + def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) + + def mkIsCons1(lTpe: Type, fhTpe0: Type, ftTpe0: Type): Tree = { + val lParam = lTpe.typeParams.head + val lParamTpe = lParam.asType.toType + val lDealiasedTpe = appliedType(lTpe, lParamTpe).dealias + + val (fhTpe, ftTpe) = c.openImplicits.headOption match { + case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, fh, ft)), _)) => (fh, ft) + case _ => (fhTpe0, ftTpe0) + } + + if (!(lDealiasedTpe.typeConstructor =:= consTpe)) + abort("Not H/CCons") + + val TypeRef(_, _, List(hd, tl)) = (lDealiasedTpe: @unchecked) + val hdPoly = polyType(List(lParam), hd) + val tlPoly = polyType(List(lParam), tl) + val name = TypeName(c.freshName()) + val hdTpt = appliedTypTree1(hdPoly, lParamTpe, name) + val tlTpt = appliedTypTree1(tlPoly, lParamTpe, name) + val hdName = TypeName(c.freshName("H")) + val tlName = TypeName(c.freshName("T")) + val (pack, unpack) = mkPackUnpack(hdName, tlName) + + q""" + type $hdName[$name] = $hdTpt + type $tlName[$name] = $tlTpt + $isCons1TC.unsafeInstance[$lTpe, $fhTpe, $ftTpe, $hdName, $tlName]($pack, $unpack) + """ + } +} + +class Split1Macros(val c: whitebox.Context) extends CaseClassMacros { + import c.ImplicitCandidate + import c.internal._ + import c.universe._ + + def mkSplit1Impl[L[_], FO[_[_]], FI[_[_]]] + (implicit lTag: WeakTypeTag[L[_]], foTag: WeakTypeTag[FO[Any]], fiTag: WeakTypeTag[FI[Any]]): Tree = { + val lTpe = lTag.tpe + + val (foTpe, fiTpe) = c.openImplicits.headOption match { + case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, fo, fi)), _)) => (fo, fi) + case _ => (foTag.tpe.typeConstructor, fiTag.tpe.typeConstructor) + } + + if (isReprType1(lTpe)) + abort("No Split1 instance available for HList or Coproduct") + + val lParam = lTpe.typeParams.head + val lParamTpe = lParam.asType.toType + val lDealiasedTpe = appliedType(lTpe, lParamTpe).dealias + + def balanced(args: List[Type]): Boolean = + args.find(_.contains(lParam)).exists { pivot => + !(pivot =:= lParamTpe) && args.forall { arg => + arg =:= pivot || !arg.contains(lParam) + } + } + + val name = TypeName(c.freshName()) + val (oTpt, iTpt) = lDealiasedTpe match { + case tpe @ TypeRef(_, _, args) if balanced(args) => + val pivot = args.find(_.contains(lParam)).get + val oPoly = polyType(List(lParam), appliedType(tpe.typeConstructor, args.map(arg => if (arg =:= pivot) lParamTpe else arg))) + val oTpt = appliedTypTree1(oPoly, lParamTpe, name) + val iPoly = polyType(List(lParam), pivot) + val iTpt = appliedTypTree1(iPoly, lParamTpe, name) + (oTpt, iTpt) + case other => + c.abort(c.enclosingPosition, s"Can't split $other into a non-trivial outer and inner type constructor") + } + + val oName = TypeName(c.freshName("O")) + val iName = TypeName(c.freshName("I")) + val split1 = objectRef[Split1.type] + + q""" + type $oName[$name] = $oTpt + type $iName[$name] = $iTpt + $split1.instance[$foTpe, $fiTpe, $oName, $iName] + """ + } +} diff --git a/core/src/main/scala-2/shapeless/hlists.scala b/core/src/main/scala-2/shapeless/hlists.scala new file mode 100644 index 000000000..3d21a4caf --- /dev/null +++ b/core/src/main/scala-2/shapeless/hlists.scala @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait HListScalaCompat { + + /** + * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows, + * + * {{{ + * type ISB = HList.`Int, String, Boolean`.T + * }}} + * + * Literal types are allowed, so that the following is valid, + * + * {{{ + * type ABC = HList.`'a, 'b, 'c`.T + * type TwoTrueStr = HList.`2, true, "str"`.T + * }}} + */ + def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistType +} + +trait NatProductArgsScalaCompat { + def applyDynamic(method: String)(args: Int*): Any = macro ProductMacros.forwardNatImpl +} + +trait ProductArgsScalaCompat { + def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardImpl +} + +trait FromProductArgsScalaCompat { + def applyDynamic(method: String)(hlist: HList): Any = macro ProductMacros.forwardFromProductImpl +} + +trait SingletonProductArgsScalaCompat { + def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardSingletonImpl +} + +class ProductMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { + import c.universe._ + + def forwardImpl(method: Tree)(args: Tree*): Tree = forward(method, args, false) + + def forwardNatImpl(method: Tree)(args: Tree*): Tree = forwardNat(method, args) + + def forwardSingletonImpl(method: Tree)(args: Tree*): Tree = forward(method, args, true) + + def forwardNat(method: Tree, args: Seq[Tree]): Tree = { + val lhs = c.prefix.tree + val lhsTpe = lhs.tpe + + val q"${methodString: String}" = (method: @unchecked) + val methodName = TermName(methodString+"NatProduct") + + if(lhsTpe.member(methodName) == NoSymbol) + c.abort(c.enclosingPosition, s"missing method '$methodName'") + + val meth = lhsTpe.member(methodName).asMethod + + if (!meth.paramLists.isEmpty && (meth.paramLists(0) forall (_.isImplicit))) { + val typeParamsTree = mkProductNatTypeParamsImpl(args) + q""" $lhs.$methodName[${typeParamsTree}] """ + } else { + val argsTree = mkProductNatImpl(args) + q""" $lhs.$methodName($argsTree) """ + } + } + + def forward(method: Tree, args: Seq[Tree], narrow: Boolean): Tree = { + val lhs = c.prefix.tree + val lhsTpe = lhs.tpe + + val q"${methodString: String}" = (method: @unchecked) + val methodName = TermName(methodString+"Product") + + if(lhsTpe.member(methodName) == NoSymbol) + c.abort(c.enclosingPosition, s"missing method '$methodName'") + + val argsTree = mkProductImpl(args, narrow) + + q""" $lhs.$methodName($argsTree) """ + } + + def forwardFromProductImpl(method: Tree)(hlist: Tree): Tree = { + val lhs = c.prefix.tree + val lhsTpe = lhs.tpe + + val q"${methodString: String}" = (method: @unchecked) + + if (!methodString.matches(".*Product$")) + c.abort(c.enclosingPosition, s"missing method '$methodString'") + + val methodName = TermName(methodString.replaceAll("Product$", "")) + + if(!lhsTpe.member(methodName).isMethod) + c.abort(c.enclosingPosition, s"missing method '$methodName'") + + val methodSym = lhsTpe.member(methodName).asMethod + val paramss = methodSym.paramLists.filterNot(_.forall(_.isImplicit)) + val argss = paramss.map(_.map(_ => TermName(c.freshName("pat")))) + val names = argss.flatten + + val pattern = + names.foldRight(q"_root_.shapeless.HNil": Tree) { + case (nme, acc) => pq"_root_.shapeless.::($nme, $acc)" + } + + q""" + $hlist match { + case $pattern => $lhs.$methodName(...$argss) + } + """ + } + + def mkProductImpl(args: Seq[Tree], narrow: Boolean): Tree = { + args.foldRight((hnilTpe, q"_root_.shapeless.HNil: $hnilTpe": Tree)) { + case(elem, (accTpe, accTree)) => + val (neTpe, neTree) = if(narrow) narrowValue(elem) else (elem.tpe, elem) + (appliedType(hconsTpe, List(neTpe, accTpe)), q"""_root_.shapeless.::[$neTpe, $accTpe]($neTree, $accTree)""") + }._2 + } + + def mkProductNatImpl(args: Seq[Tree]): Tree = { + args.foldRight((tq"_root_.shapeless.HNil", q"_root_.shapeless.HNil: $hnilTpe"): (Tree, Tree)) { + case(NatLiteral(n), (accTpt, accTree)) => + val neTpt = mkNatTpt(n) + val neTree = mkNatValue(n) + (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", q"""_root_.shapeless.::[$neTpt, $accTpt]($neTree, $accTree)""") + case (elem, _) => + c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") + }._2 + } + + def mkProductNatTypeParamsImpl(args: Seq[Tree]): Tree = { + args.foldRight((tq"_root_.shapeless.HNil", tq"_root_.shapeless.HNil"): (Tree, Tree)) { + case (NatLiteral(n), (accTpt, _)) => + val neTpt = mkNatTpt(n) + (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", tq"""_root_.shapeless.::[$neTpt, $accTpt]""") + case (elem, _) => + c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") + }._2 + } +} diff --git a/core/src/main/scala-2/shapeless/labelled.scala b/core/src/main/scala-2/shapeless/labelled.scala new file mode 100644 index 000000000..ab8243a34 --- /dev/null +++ b/core/src/main/scala-2/shapeless/labelled.scala @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait LabellingScalaCompat { + + implicit def mkLabelling[T]: Labelling[T] = + macro LabelledMacros.mkLabelling[T] +} + +class LabelledMacros(override val c: whitebox.Context) extends GenericMacros(c) with SingletonTypeUtils { + import c.universe._ + import internal.constantType + + private def commaSeparated(str: String): List[String] = { + val builder = List.newBuilder[String] + var i, j, k = 0 + while (j < str.length) { + str.charAt(j) match { + case ',' if k == 0 => + builder += str.substring(i, j).trim + i = j + 1 + case '(' | '[' => + k += 1 + case ')' | ']' => + k = k - 1 max 0 + case _ => + } + + j += 1 + } + + val last = str.substring(i, j).trim + if (last.nonEmpty) builder += last + builder.result() + } + + private def parseTypeOrFail(tpe: String): Type = + parseType(tpe).getOrElse(abort(s"Malformed literal or standard type $tpe")) + + private def parseLiteralTypeOrFail(tpe: String): Type = + parseLiteralType(tpe).getOrElse(abort(s"Malformed literal type $tpe")) + + private def labelsOf(tpe: Type): List[Constant] = + if (isProduct(tpe)) fieldsOf(tpe).map { case (f, _) => nameAsValue(f) } + else if (isCoproduct(tpe)) ctorsOf(tpe).map(c => nameAsValue(nameOf(c))) + else abort(s"$tpe is not case class like or the root of a sealed family of types") + + def mkLabelledGeneric[T: WeakTypeTag, R]: Tree = { + val tpe = weakTypeOf[T] + val keys = labelsOf(tpe).map(constantType) + val generic @ q"$_.instance[$_, ${repr: Tree}]($_, $_)" = (mkGeneric[T]: @unchecked) + val isProduct = repr.tpe <:< hlistTpe + val values = if (isProduct) unpackHList(repr.tpe) else unpackCoproduct(repr.tpe) + val items = keys.zip(values).map((FieldType.apply _).tupled) + val labelled = if (isProduct) mkHListTpe(items) else mkCoproductTpe(items) + q"${reify(LabelledGeneric)}.unsafeInstance[$tpe, $labelled]($generic)" + } + + def mkLabelling[T: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T] + val labels = labelsOf(tpe) + val labelsType = mkHListTpe(labels.map(constantType)) + val labelsValue = mkHListValue(labels.map(Literal.apply)) + q"${reify(Labelling)}.instance[$tpe, $labelsType]($labelsValue.asInstanceOf[$labelsType])" + } + + def recordType(tpeSelector: Tree): Tree = + labelledType(tpeSelector, "record", hnilTpe, hconsTpe) + + def unionType(tpeSelector: Tree): Tree = + labelledType(tpeSelector, "union", cnilTpe, cconsTpe) + + def labelledType(tpeSelector: Tree, variety: String, nil: Type, cons: Type): Tree = { + val q"${tpeString: String}" = (tpeSelector: @unchecked) + val labelledTpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => + element.split("->") match { + case Array(keyString, valueString) => + val key = parseLiteralTypeOrFail(keyString.trim) + val value = parseTypeOrFail(valueString.trim) + appliedType(cons, FieldType(key, value), acc) + case _ => + abort(s"Malformed $variety type $tpeString") + } + } + + typeCarrier(labelledTpe) + } + + def hlistType(tpeSelector: Tree): Tree = + nonLabelledType(tpeSelector, hnilTpe, hconsTpe) + + def coproductType(tpeSelector: Tree): Tree = + nonLabelledType(tpeSelector, cnilTpe, cconsTpe) + + def nonLabelledType(tpeSelector: Tree, nil: Type, cons: Type): Tree = { + val q"${tpeString: String}" = (tpeSelector: @unchecked) + val tpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => + appliedType(cons, parseTypeOrFail(element), acc) + } + + typeCarrier(tpe) + } +} diff --git a/core/src/main/scala-2/shapeless/lazy.scala b/core/src/main/scala-2/shapeless/lazy.scala new file mode 100644 index 000000000..93a851ce2 --- /dev/null +++ b/core/src/main/scala-2/shapeless/lazy.scala @@ -0,0 +1,5 @@ +package shapeless + +trait LazyScalaCompat[+T] { + val value: T +} diff --git a/core/src/main/scala-2/shapeless/nat.scala b/core/src/main/scala-2/shapeless/nat.scala new file mode 100644 index 000000000..1131866ba --- /dev/null +++ b/core/src/main/scala-2/shapeless/nat.scala @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.annotation.tailrec +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait NatScalaCompat { + implicit def apply(i: Int): Nat = macro NatMacros.materializeWidened +} + +class NatMacros(val c: whitebox.Context) extends NatMacroDefns { + import c.universe._ + + def materializeWidened(i: Tree): Tree = + i match { + case NatLiteral(n) => mkNatValue(n) + case _ => + c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") + } +} + +trait NatMacroDefns { + val c: whitebox.Context + import c.universe._ + + object NatLiteral { + def unapply(i: Tree): Option[Int] = + i match { + case Literal(Constant(n: Int)) if n >= 0 => Some(n) + case _ => None + } + } + + def mkNatTpt(i: Int): Tree = { + val succSym = typeOf[Succ[_]].typeConstructor.typeSymbol + val _0Sym = typeOf[_0].typeSymbol + + @tailrec + def loop(i: Int, acc: Tree): Tree = { + if(i == 0) acc + else loop(i-1, AppliedTypeTree(Ident(succSym), List(acc))) + } + + loop(i, Ident(_0Sym)) + } + + def mkNatTpe(i: Int): Type = { + val succTpe = typeOf[Succ[_]].typeConstructor + val _0Tpe = typeOf[_0] + + @tailrec + def loop(i: Int, acc: Type): Type = { + if(i == 0) acc + else loop(i-1, appliedType(succTpe, acc)) + } + + loop(i, _0Tpe) + } + + def mkNatValue(i: Int): Tree = + q""" new ${mkNatTpt(i)} """ +} diff --git a/core/src/main/scala-2/shapeless/ops/nat.scala b/core/src/main/scala-2/shapeless/ops/nat.scala new file mode 100644 index 000000000..47b671b4f --- /dev/null +++ b/core/src/main/scala-2/shapeless/ops/nat.scala @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops + +import scala.annotation.tailrec +import scala.reflect.macros.whitebox +import scala.language.experimental.macros + +trait ToIntScalaCompat { + implicit def toIntSuccM[N <: Nat]: nat.ToInt[N] = macro ToIntMacros.applyImpl[N] +} +class ToIntMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + val _0Tpe = typeOf[_0] + val succTpe = typeOf[Succ[_]].typeConstructor + val succSym = succTpe.typeSymbol + val succPre = prefix(succTpe) + + + def applyImpl[N <: Nat](implicit nTag: WeakTypeTag[N]): Tree = { + val tpe = nTag.tpe.dealias + + @tailrec + def count(u: Type, acc: Int): Int = { + if(u <:< _0Tpe) acc + else (u baseType succSym) match { + case TypeRef(pre, _, List(n)) if pre =:= succPre => count(n, acc + 1) + case _ => abort(s"$tpe is not a Nat type") + } + } + + q""" + new _root_.shapeless.ops.nat.ToInt.Inst(${count(tpe, 0)}). + asInstanceOf[ _root_.shapeless.ops.nat.ToInt[$tpe]] + """ + } +} diff --git a/core/src/main/scala-2/shapeless/ops/record/records.scala b/core/src/main/scala-2/shapeless/ops/record/records.scala new file mode 100644 index 000000000..ef0966b87 --- /dev/null +++ b/core/src/main/scala-2/shapeless/ops/record/records.scala @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops +package record + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait SelectorScalaCompat { + + implicit def materialize[R <: HList, K, O]: Selector.Aux[R, K, O] = + macro SelectorMacros.materialize[R, K] +} + +class SelectorMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { + val record = weakTypeOf[R].dealias + val key = weakTypeOf[K].dealias + if (!(record <:< hlistTpe)) + abort(s"$record is not a record type") + + findField(record, key) match { + case Some((k, v, i)) => + q"new ${typeOf[UnsafeSelector]}($i).asInstanceOf[${reify(Selector)}.Aux[$record, $k, $v]]" + case _ => + abort(s"No field $key in record type $record") + } + } +} + +trait UpdaterScalaCompat { + + implicit def meterialize[L <: HList, F, O]: Updater.Aux[L, F, O] = + macro UpdaterMacros.materialize[L, F] +} + +class UpdaterMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def materialize[L <: HList: WeakTypeTag, E: WeakTypeTag]: Tree = { + val list = weakTypeOf[L].dealias + val element = weakTypeOf[E].dealias + if (!(list <:< hlistTpe)) + abort(s"$list is not a record type") + + val (updated, i) = { + val elements = unpackHList(list) + val i = elements.indexWhere(_ =:= element) + if (i < 0) (elements :+ element, elements.length) + else (elements.updated(i, element), i) + } + + q"new ${typeOf[UnsafeUpdater]}($i).asInstanceOf[${reify(Updater)}.Aux[$list, $element, ${mkHListTpe(updated)}]]" + } +} + +trait ModifierScalaCompat { + implicit def materialize[R <: HList, K, A, B, O <: HList]: Modifier.Aux[R, K, A, B, O] = + macro ModifierMacros.materialize[R, K, A, B] +} + +class ModifierMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag, A: WeakTypeTag, B: WeakTypeTag]: Tree = { + val record = weakTypeOf[R].dealias + val key = weakTypeOf[K].dealias + if (!(record <:< hlistTpe)) + abort(s"$record is not a record type") + + val a = weakTypeOf[A] + val b = weakTypeOf[B] + val fields = unpackHList(record) + findField(fields, key) match { + case Some((k, v, i)) if v <:< a => + val out = mkHListTpe(fields.updated(i, FieldType(k, b))) + q"new ${typeOf[UnsafeModifier]}($i).asInstanceOf[${reify(Modifier)}.Aux[$record, $k, $a, $b, $out]]" + case _ => + abort(s"No field $key in record type $record") + } + } +} + +trait RemoverScalaCompat { + implicit def materialize[R <: HList, K, V, O <: HList]: Remover.Aux[R, K, (V, O)] = + macro RemoverMacros.materialize[R, K] +} + +class RemoverMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { + val record = weakTypeOf[R].dealias + val key = weakTypeOf[K].dealias + if (!(record <:< hlistTpe)) + abort(s"$record is not a record type") + + val fields = unpackHList(record) + findField(fields, key) match { + case Some((k, v, i)) => + val (prefix, suffix) = fields.splitAt(i) + val out = mkHListTpe(prefix ++ suffix.tail) + q"new ${typeOf[UnsafeRemover]}($i).asInstanceOf[${reify(Remover)}.Aux[$record, $k, ($v, $out)]]" + case _ => + abort(s"No field $key in record type $record") + } + } +} + +trait LacksKeyScalaCompat { + implicit def materialize[R <: HList, K]: LacksKey[R, K] = + macro LacksKeyMacros.materialize[R, K] +} + +class LacksKeyMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + + def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { + val record = weakTypeOf[R].dealias + val key = weakTypeOf[K].dealias + if (!(record <:< hlistTpe)) + abort(s"$record is not a record type") + + findField(record, key) match { + case None => q"new ${weakTypeOf[LacksKey[R, K]]}" + case _ => abort(s"Record type $record contains field $key") + } + } +} diff --git a/core/src/main/scala-2/shapeless/poly.scala b/core/src/main/scala-2/shapeless/poly.scala new file mode 100644 index 000000000..bb433ba4d --- /dev/null +++ b/core/src/main/scala-2/shapeless/poly.scala @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import shapeless.PolyDefns.Case + +import language.experimental.macros + +import reflect.macros.whitebox + +trait CaseScalaCompat { + + implicit def materializeFromValue1[P, F[_], T]: Case[P, F[T] :: HNil] = + macro PolyMacros.materializeFromValueImpl[P, F[T], T] + + implicit def materializeFromValue2[P, T]: Case[P, T :: HNil] = + macro PolyMacros.materializeFromValueImpl[P, T, T] +} + +class PolyMacros(val c: whitebox.Context) { + import c.universe._ + + import PolyDefns.Case + + def materializeFromValueImpl[P: WeakTypeTag, FT: WeakTypeTag, T: WeakTypeTag]: Tree = { + val pTpe = weakTypeOf[P] + val ftTpe = weakTypeOf[FT] + val tTpe = weakTypeOf[T] + + val recTpe = weakTypeOf[Case[P, FT :: HNil]] + if(c.openImplicits.tail.exists(_.pt =:= recTpe)) + c.abort(c.enclosingPosition, s"Diverging implicit expansion for Case.Aux[$pTpe, $ftTpe :: HNil]") + + val value = pTpe match { + case SingleType(_, f) => f + case other => c.abort(c.enclosingPosition, "Can only materialize cases from singleton values") + } + + q""" $value.caseUniv[$tTpe] """ + } +} diff --git a/core/src/main/scala-2/shapeless/records.scala b/core/src/main/scala-2/shapeless/records.scala new file mode 100644 index 000000000..21610fd86 --- /dev/null +++ b/core/src/main/scala-2/shapeless/records.scala @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait RecordScalaCompat { + def applyDynamic(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordEmptyImpl + def applyDynamicNamed(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordNamedImpl + def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.recordType +} + +trait RecordArgsScalaCompat { + def applyDynamic(method: String)(): Any = macro RecordMacros.forwardImpl + def applyDynamicNamed(method: String)(rec: Any*): Any = macro RecordMacros.forwardNamedImpl +} + +trait FromRecordArgsScalaCompat { + def applyDynamic[L <: HList](method: String)(rec: L): Any = macro RecordMacros.forwardFromRecordImpl[L] +} + +class RecordMacros(val c: whitebox.Context) extends CaseClassMacros { + import c.universe._ + import internal.constantType + + val hconsValueTree: Tree = reify(::).tree + val hnilValueTree: Tree = reify(HNil: HNil).tree + + def mkRecordEmptyImpl(method: Tree)(rec: Tree*): Tree = { + if (rec.nonEmpty) abort("this method must be called with named arguments") + hnilValueTree + } + + def mkRecordNamedImpl(method: Tree)(rec: Tree*): Tree = { + val q"${methodString: String}" = (method: @unchecked) + if (methodString != "apply") abort(s"this method must be called as 'apply' not '$methodString'") + mkRecordImpl(rec: _*) + } + + def forwardImpl(method: Tree)(): Tree = + forwardNamedImpl(method)() + + def forwardNamedImpl(method: Tree)(rec: Tree*): Tree = { + val lhs = c.prefix.tree + val lhsTpe = lhs.tpe + val q"${methodString: String}" = (method: @unchecked) + val methodName = TermName(methodString + "Record") + if (lhsTpe.member(methodName) == NoSymbol) + abort(s"missing method '$methodName'") + + val recTree = mkRecordImpl(rec: _*) + q"$lhs.$methodName($recTree)" + } + + def forwardFromRecordImpl[L <: HList](method: Tree)(rec: Expr[L]): Tree = { + val lhs = c.prefix.tree + val lhsTpe = lhs.tpe + val q"${methodString: String}" = (method: @unchecked) + if (!methodString.matches(".*Record$")) + abort(s"missing method '$methodString'") + + val methodName = TermName(methodString.replaceAll("Record$", "")) + if (!lhsTpe.member(methodName).isMethod) + abort(s"missing method '$methodName'") + + val params = mkParamsImpl(lhsTpe.member(methodName).asMethod, rec) + q"$lhs.$methodName(...$params)" + } + + def mkRecordImpl(rec: Tree*): Tree = { + def mkElem(key: Type, value: Tree): Tree = + q"$value.asInstanceOf[${FieldType(key, value.tpe.widen)}]" + + def promoteElem(elem: Tree): Tree = elem match { + case q"$_(${Literal(k)}, $v)" => mkElem(constantType(k), v) + case _ => abort(s"$elem has the wrong shape for a record field") + } + + rec.foldRight(hnilValueTree) { (elem, acc) => + q"$hconsValueTree(${promoteElem(elem)}, $acc)" + } + } + + def mkParamsImpl[L <: HList](method: MethodSymbol, rec: Expr[L]): List[List[Tree]] = { + val selector = reify(ops.hlist.Selector) + def mkElem(key: Type, value: Tree): Tree = + q"$selector[${rec.actualType}, ${FieldType(key, value.tpe.widen)}].apply($rec)" + + method.paramLists.filterNot(_.forall(_.isImplicit)).map(_.map { p => + mkElem(constantType(nameAsValue(p.name)), q"${p.typeSignature}") + }) + } +} diff --git a/core/src/main/scala-2/shapeless/singletons.scala b/core/src/main/scala-2/shapeless/singletons.scala new file mode 100644 index 000000000..dd06fb459 --- /dev/null +++ b/core/src/main/scala-2/shapeless/singletons.scala @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2013-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import shapeless.syntax.SingletonOps + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait WitnessScalaCompat { + def selectDynamic(tpeSelector: String): Any = + macro SingletonTypeMacros.witnessTypeImpl +} + +trait NatWithScalaCompat { + + implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = + macro SingletonTypeMacros.convertInstanceImplNat[TC] + + implicit def apply2[B, T <: B, TC[_ <: B, _ <: Nat]](i: Int): NatWith[({ type λ[t <: Nat] = TC[T, t] })#λ] = + macro SingletonTypeMacros.convertInstanceImplNat1[B, T, TC] +} + +trait WidenScalaCompat { + + implicit def apply1[TC[_], T](t: T): WitnessWith.Lt[TC, T] = macro SingletonTypeMacros.convertInstanceImpl1[TC] + + implicit def materialize[T, Out]: Widen.Aux[T, Out] = macro SingletonTypeMacros.materializeWiden[T, Out] +} + +trait SingletonTypeUtils extends ReprTypes { + import c.universe._ + import internal._ + import decorators._ + + def singletonOpsTpe: Type = typeOf[syntax.SingletonOps] + + object SingletonType { + def unapply(value: Tree): Option[Type] = (value, value.tpe) match { + case (Literal(const), _) => Some(constantType(const)) + case (_, keyType @ SingleType(_, v)) if !v.isParameter && !isValueClass(v) => Some(keyType) + case (q"${sops: Tree}.narrow", _) if sops.tpe <:< singletonOpsTpe => + Some(sops.tpe.member(TypeName("T")).typeSignature) + case _ => None + } + } + + def narrowValue(value: Tree): (Type, Tree) = value match { + case Literal(const) => + val tpe = constantType(const) + (tpe, q"$value.asInstanceOf[$tpe]") + case _ => + (value.tpe, value) + } + + def parseLiteralType(typeStr: String): Option[Type] = for { + parsed <- util.Try(c.parse(typeStr)).toOption + checked <- Option(c.typecheck(parsed, silent = true)) + if checked.nonEmpty + tpe <- SingletonType.unapply(checked) + } yield tpe + + def parseStandardType(typeStr: String): Option[Type] = for { + parsed <- util.Try(c.parse(s"null.asInstanceOf[$typeStr]")).toOption + checked <- Option(c.typecheck(parsed, silent = true)) + if checked.nonEmpty + } yield checked.tpe + + def parseType(typeStr: String): Option[Type] = + parseStandardType(typeStr) orElse parseLiteralType(typeStr) + + def typeCarrier(tpe: Type): Literal = + mkTypeCarrier(tq"{ type T = $tpe }") + + def fieldTypeCarrier(tpe: Type): Literal = + mkTypeCarrier(tq"""{ + type T = $tpe + type ->>[V] = Field[V] + type Field[V] = _root_.shapeless.labelled.FieldType[$tpe, V] + }""") + + def mkTypeCarrier(tree: Tree): Literal = { + val carrier = c.typecheck(tree, mode = c.TYPEmode).tpe + + // We can't yield a useful value here, so return Unit instead which is at least guaranteed + // to result in a runtime exception if the value is used in term position. + Literal(Constant(())).setType(carrier) + } + + def isValueClass(sym: Symbol): Boolean = { + val tSym = sym.typeSignature.typeSymbol + tSym.isClass && tSym.asClass.isDerivedValueClass + } +} + +class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { + import c.universe._ + import definitions._ + import internal._ + + def mkWitness(sTpe: Type, s: Tree): Tree = + q"${reify(Witness)}.mkWitness[$sTpe]($s.asInstanceOf[$sTpe])" + + def mkWitnessWith(tcTpe: Type, sTpe: Type, s: Tree, i: Tree): Tree = { + val witnessWith = reify(WitnessWith) + if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$witnessWith.depInstance[$tcTpe, $sTpe]($s, $i)" + else q"$witnessWith.instance[$tcTpe, $sTpe]($s, $i)" + } + + def mkWitnessNat(tcTpe: Type, nTpe: Type, tc: Tree): Tree = { + val natWith = reify(NatWith) + if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$natWith.depInstance[$tcTpe, $nTpe]($tc)" + else q"$natWith.instance[$tcTpe, $nTpe]($tc)" + } + + def mkOps(sTpe: Type, w: Tree): Tree = + q"${reify(SingletonOps)}.instance[$sTpe]($w)" + + def mkAttributedQualifier(tpe: Type): Tree = { + val global = c.universe.asInstanceOf[scala.tools.nsc.Global] + val gTpe = tpe.asInstanceOf[global.Type] + global.gen.mkAttributedQualifier(gTpe).asInstanceOf[Tree] + } + + @annotation.tailrec + final def unrefine(tpe: Type): Type = tpe.dealias match { + case RefinedType(List(parent), scope) if scope.isEmpty => unrefine(parent) + case other => other + } + + def extractSingletonValue(tpe: Type): Tree = unrefine(tpe) match { + case ConstantType(const) => Literal(const) + case singleton: SingleType => mkAttributedQualifier(singleton) + case ThisType(sym) => This(sym) + case ref @ TypeRef(_, sym, _) if sym.isModuleClass => mkAttributedQualifier(ref) + case _ => c.abort(c.enclosingPosition, s"Type argument $tpe is not a singleton type") + } + + def materializeImpl[T: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T].dealias + mkWitness(tpe, extractSingletonValue(tpe)) + } + + def extractResult(value: Tree)(mkResult: (Type, Tree) => Tree): Tree = + (value.tpe, value) match { + case (tpe @ ConstantType(const), _) => + mkResult(tpe, Literal(const)) + + case (tpe: SingleType, tree) => + mkResult(tpe, tree) + + case (_, tree: This) => + mkResult(thisType(tree.symbol), tree) + + case (_, tree) if (tree.symbol ne null) && tree.symbol.isTerm && tree.symbol.asTerm.isStable => + val sym = tree.symbol.asTerm + val pre = if (sym.owner.isClass) thisType(sym.owner) else NoPrefix + val symTpe = singleType(pre, sym) + mkResult(symTpe, q"$sym.asInstanceOf[$symTpe]") + + case _ => + c.abort(c.enclosingPosition, s"Expression $value does not evaluate to a constant or a stable reference value") + } + + def convertImpl(t: Tree): Tree = extractResult(t)(mkWitness) + + def inferInstance(tci: Type): Tree = { + val inferred = c.inferImplicitValue(tci) + if (inferred == EmptyTree) + c.abort(c.enclosingPosition, s"Unable to resolve implicit value of type $tci") + inferred + } + + def convertInstanceImplNat[TC[_ <: Nat]](i: Tree)( + implicit tcTag: WeakTypeTag[TC[Nothing]] + ): Tree = convertInstanceImplNatAux(i, tcTag.tpe) + + def convertInstanceImplNat1[B, T <: B, TC[_ <: B, _ <: Nat]](i: Tree)( + implicit tTag: WeakTypeTag[T], tcTag: WeakTypeTag[TC[Nothing, Nothing]] + ): Tree = { + val tTpe = tTag.tpe + val tc = tcTag.tpe.typeConstructor + val tcParam = tc.typeParams(1) + val tcTpe = polyType(List(tcParam), appliedType(tc, tTpe, tcParam.asType.toType)) + convertInstanceImplNatAux(i, tcTpe) + } + + def convertInstanceImplNatAux(i: Tree, tcTpe: Type): Tree = { + val nTpe = i match { + case NatLiteral(n) => mkNatTpe(n) + case _ => c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") + } + + val instTpe = appliedType(tcTpe, nTpe) + val iInst = inferInstance(instTpe) + mkWitnessNat(tcTpe, nTpe, iInst) + } + + def convertInstanceImpl1[TC[_]](t: Tree)( + implicit tcTag: WeakTypeTag[TC[_]] + ): Tree = extractResult(t) { (sTpe, value) => + val tc = tcTag.tpe.typeConstructor + val tci = appliedType(tc, sTpe) + val i = inferInstance(tci) + mkWitnessWith(tc, sTpe, value, i) + } + + def convertInstanceImpl2[H, TC2[_ <: H, _], S <: H](t: Tree)( + implicit tc2Tag: WeakTypeTag[TC2[_, _]], sTag: WeakTypeTag[S] + ): Tree = extractResult(t) { (sTpe, value) => + val tc2 = tc2Tag.tpe.typeConstructor + val tparam = tc2.typeParams.last.asType + val tc = polyType(tparam :: Nil, appliedType(tc2, sTag.tpe, tparam.toType)) + val tci = appliedType(tc2, sTag.tpe, sTpe) + val i = inferInstance(tci) + mkWitnessWith(tc, sTpe, value, i) + } + + def mkSingletonOps(t: Tree): Tree = + extractResult(t) { (tpe, tree) => mkOps(tpe, mkWitness(tpe, tree)) } + + def witnessTypeImpl(tpeSelector: Tree): Tree = { + val q"${tpeString: String}" = (tpeSelector: @unchecked) + val tpe = parseLiteralType(tpeString) + .getOrElse(c.abort(c.enclosingPosition, s"Malformed literal $tpeString")) + + fieldTypeCarrier(tpe) + } + + def materializeWiden[T: WeakTypeTag, Out: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T].dealias + val wideTpe = tpe.widen + if (wideTpe =:= tpe) c.abort(c.enclosingPosition, s"Don't know how to widen $tpe") + else q"${reify(Widen)}.instance[$tpe, $wideTpe](${reify(Predef)}.identity)" + } +} diff --git a/core/src/main/scala/shapeless/test/compiletime.scala b/core/src/main/scala-2/shapeless/test/compiletime.scala similarity index 100% rename from core/src/main/scala/shapeless/test/compiletime.scala rename to core/src/main/scala-2/shapeless/test/compiletime.scala diff --git a/core/src/main/scala/shapeless/test/package.scala b/core/src/main/scala-2/shapeless/test/package.scala similarity index 100% rename from core/src/main/scala/shapeless/test/package.scala rename to core/src/main/scala-2/shapeless/test/package.scala diff --git a/core/src/main/scala/shapeless/test/typechecking.scala b/core/src/main/scala-2/shapeless/test/typechecking.scala similarity index 100% rename from core/src/main/scala/shapeless/test/typechecking.scala rename to core/src/main/scala-2/shapeless/test/typechecking.scala diff --git a/core/src/main/scala/shapeless/test/typetrace.scala b/core/src/main/scala-2/shapeless/test/typetrace.scala similarity index 100% rename from core/src/main/scala/shapeless/test/typetrace.scala rename to core/src/main/scala-2/shapeless/test/typetrace.scala diff --git a/core/src/main/scala-2/shapeless/typeable.scala b/core/src/main/scala-2/shapeless/typeable.scala new file mode 100644 index 000000000..65094bad7 --- /dev/null +++ b/core/src/main/scala-2/shapeless/typeable.scala @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011-18 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox + +trait LowPriorityTypeableScalaCompat { + implicit def dfltTypeable[T]: Typeable[T] = macro TypeableMacros.dfltTypeableImpl[T] +} + +class TypeableMacros(val c: blackbox.Context) extends SingletonTypeUtils { + import c.universe._ + import definitions.NothingClass + + val typeableTpe: Type = typeOf[Typeable[_]].typeConstructor + val genericTpe: Type = typeOf[Generic[_]].typeConstructor + + def dfltTypeableImpl[T: WeakTypeTag]: Tree = { + val tpe = weakTypeOf[T] + val dealiased = tpe.dealias + + dealiased match { + case t: TypeRef if t.sym == NothingClass => + c.abort(c.enclosingPosition, "No Typeable for Nothing") + + case ExistentialType(_, _) => + val tArgs = dealiased.typeArgs + val normalized = appliedType(dealiased.typeConstructor, tArgs) + val normalizedTypeable = c.inferImplicitValue(appliedType(typeableTpe, List(normalized))) + if (normalizedTypeable.isEmpty) + c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") + normalizedTypeable + + case RefinedType(parents, decls) => + if (decls.nonEmpty) + c.abort(c.enclosingPosition, "No Typeable for a refinement with non-empty decls") + val parentTypeables = parents.filterNot(_ =:= typeOf[AnyRef]).map { parent => + c.inferImplicitValue(appliedType(typeableTpe, List(parent))) + } + if (parentTypeables.exists(_.isEmpty)) + c.abort(c.enclosingPosition, "Missing Typeable for parent of a refinement") + + q"""_root_.shapeless.Typeable.intersectionTypeable( + _root_.scala.Array[_root_.shapeless.Typeable[_]](..$parentTypeables) + )""" + + case pTpe if pTpe.typeArgs.nonEmpty => + val pSym = { + val sym = pTpe.typeSymbol + if (!sym.isClass) + c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") + + val pSym0 = sym.asClass + pSym0.typeSignature // Workaround for + + pSym0 + } + + if(!pSym.isCaseClass) + c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") + else + mkCaseClassTypeable(tpe) + + case SingleType(_, v) if !v.isParameter => + q"""_root_.shapeless.Typeable.referenceSingletonTypeable[$tpe]( + $v.asInstanceOf[$tpe], ${nameOf(v)}, serializable = ${v.isModule} + )""" + + case ConstantType(c) => + q"""_root_.shapeless.Typeable.valueSingletonTypeable[$tpe]($c.asInstanceOf[$tpe], ${nameOf(c.tpe)})""" + + // Outer#Inner is unsound in general since Inner can capture type members of Outer. + case TypeRef(TypeRef(_, outer, args), inner, _) if !outer.isFinal || args.nonEmpty => + if (inner.isClass && inner.asClass.isCaseClass) mkCaseClassTypeable(tpe) + else c.abort(c.enclosingPosition, s"No default Typeable for type projection $tpe") + + case _ => + val tsym = tpe.typeSymbol + if (tsym.isStatic || tsym.isFinal || (tsym.isClass && tsym.asClass.isTrait)) { + // scala/bug#4440 Final inner classes and traits have no outer accessor. + q"_root_.shapeless.Typeable.namedSimpleTypeable(_root_.scala.Predef.classOf[$tpe], ${nameOf(tsym)})" + } else { + q"_root_.shapeless.Typeable.partialFunctionTypeable({ case x: $tpe => x }, ${nameOf(tsym)})" + } + } + } + + private def mkCaseClassTypeable(tpe: Type): Tree = { + // an unsafe accessor is one that isn't a case class accessor but has an abstract type. + def isUnsafeAccessor(sym: TermSymbol): Boolean = { + + if (sym.isCaseAccessor) { + false + } else { + val symType = sym.typeSignature.typeSymbol + val isAbstract = + symType.isAbstract || // Under Scala 2.10, isAbstract is spuriously false (macro-compat issue?) + (symType != NoSymbol && symType.owner == tpe.typeSymbol) // So check the owner as well + + if (isAbstract) { + sym.isVal || + sym.isVar || + (sym.isParamAccessor && !(sym.accessed.isTerm && sym.accessed.asTerm.isCaseAccessor)) + } else false + } + } + + val nonCaseAccessor = tpe.decls.exists { + case sym: TermSymbol if isUnsafeAccessor(sym) => true + case _ => false + } + if (nonCaseAccessor) { + // there is a symbol, which is not a case accessor but a val, + // var or param, so we won't be able to type check it safely: + c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") + } + val fields = tpe.decls.sorted collect { + case sym: TermSymbol if sym.isVal && sym.isCaseAccessor => sym.typeSignatureIn(tpe) + } + val fieldTypeables = fields.map { field => c.inferImplicitValue(appliedType(typeableTpe, List(field))) } + if(fieldTypeables.contains(EmptyTree)) + c.abort(c.enclosingPosition, "Missing Typeable for field of a case class") + + q""" _root_.shapeless.Typeable.namedCaseClassTypeable( + _root_.scala.Predef.classOf[$tpe], _root_.scala.Array[_root_.shapeless.Typeable[_]](..$fieldTypeables), ${nameOf(tpe)} + )""" + } + + private def nameOf(sym: Symbol): String = + sym.name.decodedName.toString + + private def nameOf(tpe: Type): String = + nameOf(tpe.typeSymbol) +} diff --git a/core/src/main/scala-2/shapeless/typeoperators.scala b/core/src/main/scala-2/shapeless/typeoperators.scala new file mode 100644 index 000000000..a73e7db25 --- /dev/null +++ b/core/src/main/scala-2/shapeless/typeoperators.scala @@ -0,0 +1,79 @@ +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox +import scala.util.{Failure, Success, Try} + +trait theScalaCompat { + def apply[T](implicit t: T): T = macro TheMacros.applyImpl + + def selectDynamic(tpeSelector: String): Any = macro TheMacros.implicitlyImpl +} + +class TheMacros(val c: whitebox.Context) { + import c.universe.{ Try => _, _ } + import internal._, decorators._ + + def applyImpl(t: Tree): Tree = t + + def implicitlyImpl(tpeSelector: Tree): Tree = { + + val q"${tpeString: String}" = (tpeSelector: @unchecked) + val dummyNme = c.freshName() + + val tpe = + (for { + parsed <- Try(c.parse(s"{ type $dummyNme = "+tpeString+" }")).toOption + checked = c.typecheck(parsed, silent = true) + if checked.nonEmpty + } yield { + val q"{ type $dummyNme = $tpt }" = (checked: @unchecked) + tpt.tpe + }).getOrElse(c.abort(c.enclosingPosition, s"Malformed type $tpeString")) + + // Bail for primitives because the resulting trees with type set to Unit + // will crash the compiler + if(tpe.typeSymbol.asClass.isPrimitive) + c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context") + + + Try(c.typecheck(q"_root_.shapeless.the.apply[$tpe]")) match { + case Success(x) => + // We can't yield a useful value here, so return Unit instead which is at least guaranteed + // to result in a runtime exception if the value is used in term position. + Literal(Constant(())).setType(x.tpe) + case Failure(e) => c.abort(c.enclosingPosition, e.getMessage) + } + } +} + +trait TypeOfScalaCompat { + def selectDynamic(code: String): Any = macro TypeOfMacros.selectDynamic +} + +private[shapeless] final class TypeOfMacros(val c: whitebox.Context) { + import c.universe.{Try => _, _} + import internal._, decorators._ + + def selectDynamic(code: Tree): Tree = { + + val q"${codeString: String}" = (code: @unchecked) + val tpe = c.parse(codeString) match { + case Typed(expr, tpt) => + val baseType = c.typecheck(tpt, mode = c.TYPEmode) + c.typecheck(expr, pt = baseType.tpe).tpe + case expr => + c.typecheck(expr).tpe + } + + // Bail for primitives because the resulting trees with type set to Unit + // will crash the compiler + val symbol = tpe.typeSymbol + if (symbol.isClass && symbol.asClass.isPrimitive) + c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context") + + // We can't yield a useful value here, so return Unit instead which is at least guaranteed + // to result in a runtime exception if the value is used in term position. + Literal(Constant(())).setType(tpe) + } +} diff --git a/core/src/main/scala-2/shapeless/unions.scala b/core/src/main/scala-2/shapeless/unions.scala new file mode 100644 index 000000000..c3e444a8c --- /dev/null +++ b/core/src/main/scala-2/shapeless/unions.scala @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.language.experimental.macros +import scala.reflect.macros.whitebox + +trait UnionScalaCompat { + def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = macro UnionMacros.mkUnionNamedImpl[U] + def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.unionType +} + +class UnionMacros(val c: whitebox.Context) { + import c.universe._ + import internal.constantType + import labelled.FieldType + + def mkUnionNamedImpl[U <: Coproduct : WeakTypeTag](method: Tree)(elems: Tree*): Tree = { + val fieldTypeTpe = typeOf[FieldType[_, _]].typeConstructor + val coproduct = reify(Coproduct) + + def mkFieldTpe(keyTpe: Type, valueTpe: Type): Type = + appliedType(fieldTypeTpe, List(keyTpe, valueTpe.widen)) + + def mkElem(keyTpe: Type, value: Tree): Tree = + q"$value.asInstanceOf[${mkFieldTpe(keyTpe, value.tpe)}]" + + def promoteElem(elem: Tree): Tree = elem match { + case q"$_(${Literal(k)}, $v)" => mkElem(constantType(k), v) + case _ => c.abort(c.enclosingPosition, s"$elem has the wrong shape for a record field") + } + + val q"${methodString: String}" = (method: @unchecked) + if (methodString != "apply") + c.abort(c.enclosingPosition, s"this method must be called as 'apply' not '$methodString'") + + val elem = elems match { + case Seq(e) => e + case _ => c.abort(c.enclosingPosition, "only one branch of a union may be inhabited") + } + + q"$coproduct[${weakTypeOf[U]}](${promoteElem(elem)})" + } +} diff --git a/core/src/main/scala-3/shapeless/annotation.scala b/core/src/main/scala-3/shapeless/annotation.scala new file mode 100644 index 000000000..375a7fb54 --- /dev/null +++ b/core/src/main/scala-3/shapeless/annotation.scala @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015-9 Alexandre Archambault + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait AnnotationScalaCompat { + implicit def materialize[A, T]: Annotation[A, T] = ??? + implicit def materializeOption[A, T]: Annotation[Option[A], T] = ??? +} + +trait AnnotationsScalaCompat { + implicit def materialize[A, T, Out <: HList]: Annotations.Aux[A, T, Out] = ??? +} + +trait TypeAnnotationsScalaCompat { + implicit def materialize[A, T, Out <: HList]: TypeAnnotations.Aux[A, T, Out] = ??? +} + +trait AllAnnotationsScalaCompat { + implicit def materialize[T, Out <: HList]: AllAnnotations.Aux[T, Out] = ??? +} + +trait AllTypeAnnotationsScalaCompat { + implicit def materialize[T, Out <: HList]: AllTypeAnnotations.Aux[T, Out] = ??? +} diff --git a/core/src/main/scala-3/shapeless/coproduct.scala b/core/src/main/scala-3/shapeless/coproduct.scala new file mode 100644 index 000000000..c5cd4ef3a --- /dev/null +++ b/core/src/main/scala-3/shapeless/coproduct.scala @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013-14 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait CoproductScalaCompat { + + /** + * Allows to specify a `Coproduct` type with a syntax similar to `Record` and `Union`, as follows, + * + * {{{ + * type ISB = Coproduct.`Int, String, Boolean`.T + * }}} + * + * Literal types are allowed, so that the following is valid, + * + * {{{ + * type ABC = Coproduct.`'a, 'b, 'c`.T + * type TwoTrueStr = Coproduct.`2, true, "str"`.T + * }}} + */ + def selectDynamic(tpeSelector: String): Any = ??? +} diff --git a/core/src/main/scala-3/shapeless/default.scala b/core/src/main/scala-3/shapeless/default.scala new file mode 100644 index 000000000..ef91bfb9e --- /dev/null +++ b/core/src/main/scala-3/shapeless/default.scala @@ -0,0 +1,5 @@ +package shapeless + +trait DefaultScalaCompat { + implicit def materialize[T, L <: HList]: Default.Aux[T, L] = ??? +} diff --git a/core/src/main/scala-3/shapeless/generic.scala b/core/src/main/scala-3/shapeless/generic.scala new file mode 100644 index 000000000..7dd1136fe --- /dev/null +++ b/core/src/main/scala-3/shapeless/generic.scala @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012-18 Lars Hupel, Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait GenericScalaCompat { + + implicit def materialize[T, R]: Generic.Aux[T, R] = ??? +} + +trait LabelledGenericScalaCompat { + + implicit def materialize[T, R]: LabelledGeneric.Aux[T, R] = ??? +} + +trait IsTupleScalaCompat { + implicit def apply[T]: IsTuple[T] = ??? +} + +trait HasProductGenericScalaCompat { + implicit def apply[T]: HasProductGeneric[T] = ??? +} + +trait HasCoproductGenericScalaCompat { + implicit def apply[T]: HasCoproductGeneric[T] = ??? +} diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala new file mode 100644 index 000000000..2639447ae --- /dev/null +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015-18 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait Generic1ScalaCompat { + + implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] = ??? + + implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[U, t] })#λ] = ??? +} + +trait Generic10ScalaCompat { + implicit def apply[T[_], FR[_[_]]]: Generic1[T, FR] = ??? +} + +trait IsHCons1ScalaCompat { + + implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = ??? + + implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = ??? + + implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = ??? + + implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = ??? +} + +trait IsHCons10ScalaCompat { + implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = ??? +} + +trait IsCCons1ScalaCompat { + + implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = ??? + + implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = ??? + + implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = ??? + + implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = ??? +} + +trait IsCCons10ScalaCompat { + implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsCCons1[L, FH, FT] = ??? +} + +trait Split1ScalaCompat { + + implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] = ??? + + implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] = ??? + + implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] = ??? + + implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] = ??? +} + +trait Split10ScalaCompat { + implicit def apply[L[_], FO[_[_]], FI[_[_]]]: Split1[L, FO, FI] = ??? +} diff --git a/core/src/main/scala-3/shapeless/hlists.scala b/core/src/main/scala-3/shapeless/hlists.scala new file mode 100644 index 000000000..dcdf0a60b --- /dev/null +++ b/core/src/main/scala-3/shapeless/hlists.scala @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait HListScalaCompat { + + /** + * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows, + * + * {{{ + * type ISB = HList.`Int, String, Boolean`.T + * }}} + * + * Literal types are allowed, so that the following is valid, + * + * {{{ + * type ABC = HList.`'a, 'b, 'c`.T + * type TwoTrueStr = HList.`2, true, "str"`.T + * }}} + */ + def selectDynamic(tpeSelector: String): Any = ??? +} + +trait NatProductArgsScalaCompat { + def applyDynamic(method: String)(args: Int*): Any = ??? +} + +trait ProductArgsScalaCompat { + def applyDynamic(method: String)(args: Any*): Any = ??? +} + +trait FromProductArgsScalaCompat { + def applyDynamic(method: String)(hlist: HList): Any = ??? +} + +trait SingletonProductArgsScalaCompat { + def applyDynamic(method: String)(args: Any*): Any = ??? +} diff --git a/core/src/main/scala-3/shapeless/labelled.scala b/core/src/main/scala-3/shapeless/labelled.scala new file mode 100644 index 000000000..70527df20 --- /dev/null +++ b/core/src/main/scala-3/shapeless/labelled.scala @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait LabellingScalaCompat { + + implicit def mkLabelling[T]: Labelling[T] = ??? +} diff --git a/core/src/main/scala-3/shapeless/lazy.scala b/core/src/main/scala-3/shapeless/lazy.scala new file mode 100644 index 000000000..6644b6495 --- /dev/null +++ b/core/src/main/scala-3/shapeless/lazy.scala @@ -0,0 +1,5 @@ +package shapeless + +trait LazyScalaCompat[+T] { + lazy val value: T +} diff --git a/core/src/main/scala-3/shapeless/nat.scala b/core/src/main/scala-3/shapeless/nat.scala new file mode 100644 index 000000000..674bb98d1 --- /dev/null +++ b/core/src/main/scala-3/shapeless/nat.scala @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait NatScalaCompat { + implicit def apply(i: Int): Nat = ??? +} diff --git a/core/src/main/scala-3/shapeless/ops/nat.scala b/core/src/main/scala-3/shapeless/ops/nat.scala new file mode 100644 index 000000000..d0b2b765e --- /dev/null +++ b/core/src/main/scala-3/shapeless/ops/nat.scala @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops + +trait ToIntScalaCompat { + implicit def toIntSuccM[N <: Nat]: nat.ToInt[N] = ??? +} diff --git a/core/src/main/scala-3/shapeless/ops/record/records.scala b/core/src/main/scala-3/shapeless/ops/record/records.scala new file mode 100644 index 000000000..8a94832be --- /dev/null +++ b/core/src/main/scala-3/shapeless/ops/record/records.scala @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops +package record + +trait SelectorScalaCompat { + + implicit def materialize[R <: HList, K, O]: Selector.Aux[R, K, O] = ??? +} + +trait UpdaterScalaCompat { + + implicit def meterialize[L <: HList, F, O <: HList]: Updater.Aux[L, F, O] = ??? +} + +trait ModifierScalaCompat { + implicit def materialize[R <: HList, K, A, B, O <: HList]: Modifier.Aux[R, K, A, B, O] = ??? +} + +trait RemoverScalaCompat { + implicit def materialize[R <: HList, K, V, O <: HList]: Remover.Aux[R, K, (V, O)] = ??? +} + +trait LacksKeyScalaCompat { + implicit def materialize[R <: HList, K]: LacksKey[R, K] = ??? +} diff --git a/core/src/main/scala-3/shapeless/poly.scala b/core/src/main/scala-3/shapeless/poly.scala new file mode 100644 index 000000000..3889e2dd6 --- /dev/null +++ b/core/src/main/scala-3/shapeless/poly.scala @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import shapeless.PolyDefns.Case + +trait CaseScalaCompat { + + implicit def materializeFromValue1[P, F[_], T]: Case[P, F[T] :: HNil] = ??? + + implicit def materializeFromValue2[P, T]: Case[P, T :: HNil] = ??? +} diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala new file mode 100644 index 000000000..936a00a95 --- /dev/null +++ b/core/src/main/scala-3/shapeless/records.scala @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait RecordScalaCompat { + def applyDynamic(method: String)(rec: Any*): HList = ??? + def applyDynamicNamed(method: String)(rec: Any*): HList = ??? + def selectDynamic(tpeSelector: String): Any = ??? +} + +trait RecordArgsScalaCompat { + def applyDynamic(method: String)(): Any = ??? + def applyDynamicNamed(method: String)(rec: Any*): Any = ??? +} + +trait FromRecordArgsScalaCompat { + def applyDynamic[L <: HList](method: String)(rec: L): Any = ??? +} diff --git a/core/src/main/scala-3/shapeless/singletons.scala b/core/src/main/scala-3/shapeless/singletons.scala new file mode 100644 index 000000000..dfd44a404 --- /dev/null +++ b/core/src/main/scala-3/shapeless/singletons.scala @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait WitnessScalaCompat { + def selectDynamic(tpeSelector: String): Any = ??? +} + +trait NatWithScalaCompat { + + implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = ??? + + implicit def apply2[B, T <: B, TC[_ <: B, _ <: Nat]](i: Int): NatWith[({ type λ[t <: Nat] = TC[T, t] })#λ] = ??? +} + +trait WidenScalaCompat { + + implicit def apply1[TC[_], T](t: T): WitnessWith.Lt[TC, T] = ??? + + implicit def materialize[T, Out >: T]: Widen.Aux[T, Out] = ??? +} diff --git a/core/src/main/scala-3/shapeless/typeable.scala b/core/src/main/scala-3/shapeless/typeable.scala new file mode 100644 index 000000000..96dedde07 --- /dev/null +++ b/core/src/main/scala-3/shapeless/typeable.scala @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011-18 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait LowPriorityTypeableScalaCompat { + implicit def dfltTypeable[T]: Typeable[T] = ??? +} diff --git a/core/src/main/scala-3/shapeless/typeoperators.scala b/core/src/main/scala-3/shapeless/typeoperators.scala new file mode 100644 index 000000000..ea44a6b3c --- /dev/null +++ b/core/src/main/scala-3/shapeless/typeoperators.scala @@ -0,0 +1,11 @@ +package shapeless + +trait theScalaCompat { + def apply[T](implicit t: T): T = ??? + + def selectDynamic(tpeSelector: String): Any = ??? +} + +trait TypeOfScalaCompat { + def selectDynamic(code: String): Any = ??? +} diff --git a/core/src/main/scala-3/shapeless/unions.scala b/core/src/main/scala-3/shapeless/unions.scala new file mode 100644 index 000000000..df6398de8 --- /dev/null +++ b/core/src/main/scala-3/shapeless/unions.scala @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait UnionScalaCompat { + def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = ??? + def selectDynamic(tpeSelector: String): Any = ??? +} diff --git a/core/src/main/scala-3/shapeless/versionspecifics.scala b/core/src/main/scala-3/shapeless/versionspecifics.scala new file mode 100644 index 000000000..8eba3848d --- /dev/null +++ b/core/src/main/scala-3/shapeless/versionspecifics.scala @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +trait LazyInstances { + implicit def mkLazy[I](implicit i: => I): Lazy[I] = Lazy(i) +} + +trait StrictInstances { + implicit def mkStrict[I](implicit i: I): Strict[I] = Strict(i) +} + +trait WitnessInstances { + implicit def of[T: ValueOf]: Witness.Aux[T] = + Witness.mkWitness(valueOf[T]) + + implicit def apply[T](t: T): Witness.Aux[t.type] = + Witness.mkWitness[t.type](t) +} + +trait WitnessWithInstances { + implicit def apply[TC[_], T](t: T)(implicit tc: TC[t.type]): WitnessWith.Aux[TC, t.type] { val instance: tc.type } = + instance[TC, t.type](t, tc) + + def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = + new WitnessWith[TC] { + type T = A + val value: T = v + val instance: tc.type = tc + } +} + +trait ScalaVersionSpecifics { + private[shapeless] type IsRegularIterable[Repr] = collection.generic.IsIterable[Repr] { type C = Repr } + + def cachedImplicit[T]: T = ??? +} diff --git a/core/src/main/scala/shapeless/alacarte.scala b/core/src/main/scala/shapeless/alacarte.scala index 018bf9366..58bf32e45 100644 --- a/core/src/main/scala/shapeless/alacarte.scala +++ b/core/src/main/scala/shapeless/alacarte.scala @@ -134,28 +134,28 @@ trait ToStringFacet extends ProductFacet { } } -trait DefaultCaseClassDefns extends - ApplyUnapplyFacet with - ProductFacet with - PolymorphicEqualityFacet with - CopyFacet with - ToStringFacet { - - trait CaseClassOps extends - ApplyUnapplyOps with - ProductOps with - PolymorphicEqualityOps with - CopyOps with - ToStringOps +trait DefaultCaseClassDefns + extends ApplyUnapplyFacet + with ProductFacet + with PolymorphicEqualityFacet + with CopyFacet + with ToStringFacet { + + trait CaseClassOps + extends ApplyUnapplyOps + with ProductOps + with PolymorphicEqualityOps + with CopyOps + with ToStringOps trait CaseClassCompanion extends ApplyUnapplyCompanion - trait CaseClass extends - ProductMethods with - PolymorphicEqualityMethods with - CopyMethods with - ToStringMethods { self: C => } + trait CaseClass + extends ProductMethods + with PolymorphicEqualityMethods + with CopyMethods + with ToStringMethods { self: C => } val ops: CaseClassOps diff --git a/core/src/main/scala/shapeless/annotation.scala b/core/src/main/scala/shapeless/annotation.scala index 64c012904..a1447e5e9 100644 --- a/core/src/main/scala/shapeless/annotation.scala +++ b/core/src/main/scala/shapeless/annotation.scala @@ -16,9 +16,6 @@ package shapeless -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - /** * Evidence that type `T` has annotation `A`, and provides an instance of the annotation. * @@ -45,16 +42,13 @@ trait Annotation[A, T] extends Serializable { def apply(): A } -object Annotation { +object Annotation extends AnnotationScalaCompat { def apply[A,T](implicit annotation: Annotation[A, T]): Annotation[A, T] = annotation def mkAnnotation[A, T](annotation: => A): Annotation[A, T] = new Annotation[A, T] { def apply(): A = annotation } - - implicit def materialize[A, T]: Annotation[A, T] = macro AnnotationMacros.materializeAnnotationRequired[A, T] - implicit def materializeOption[A, T]: Annotation[Option[A], T] = macro AnnotationMacros.materializeAnnotationOptional[A, T] } /** @@ -104,7 +98,7 @@ trait Annotations[A,T] extends DepFn0 with Serializable { type Out <: HList } -object Annotations { +object Annotations extends AnnotationsScalaCompat { def apply[A,T](implicit annotations: Annotations[A,T]): Aux[A, T, annotations.Out] = annotations type Aux[A, T, Out0 <: HList] = Annotations[A, T] { type Out = Out0 } @@ -114,8 +108,6 @@ object Annotations { type Out = Out0 def apply(): Out = annotations } - - implicit def materialize[A, T, Out <: HList]: Aux[A, T, Out] = macro AnnotationMacros.materializeVariableAnnotations[A, T, Out] } /** @@ -158,7 +150,7 @@ trait TypeAnnotations[A,T] extends DepFn0 with Serializable { type Out <: HList } -object TypeAnnotations { +object TypeAnnotations extends TypeAnnotationsScalaCompat { def apply[A,T](implicit annotations: TypeAnnotations[A,T]): Aux[A, T, annotations.Out] = annotations type Aux[A, T, Out0 <: HList] = TypeAnnotations[A, T] { type Out = Out0 } @@ -168,8 +160,6 @@ object TypeAnnotations { type Out = Out0 def apply(): Out = annotations } - - implicit def materialize[A, T, Out <: HList]: Aux[A, T, Out] = macro AnnotationMacros.materializeTypeAnnotations[A, T, Out] } /** @@ -212,7 +202,7 @@ trait AllAnnotations[T] extends DepFn0 with Serializable { type Out <: HList } -object AllAnnotations { +object AllAnnotations extends AllAnnotationsScalaCompat { def apply[T](implicit annotations: AllAnnotations[T]): Aux[T, annotations.Out] = annotations type Aux[T, Out0 <: HList] = AllAnnotations[T] { type Out = Out0 } @@ -222,8 +212,6 @@ object AllAnnotations { type Out = Out0 def apply(): Out = annotations } - - implicit def materialize[T, Out <: HList]: Aux[T, Out] = macro AnnotationMacros.materializeAllVariableAnnotations[T, Out] } /** @@ -266,7 +254,7 @@ trait AllTypeAnnotations[T] extends DepFn0 with Serializable { type Out <: HList } -object AllTypeAnnotations { +object AllTypeAnnotations extends AllTypeAnnotationsScalaCompat { def apply[T](implicit annotations: AllTypeAnnotations[T]): Aux[T, annotations.Out] = annotations type Aux[T, Out0 <: HList] = AllTypeAnnotations[T] { type Out = Out0 } @@ -276,178 +264,4 @@ object AllTypeAnnotations { type Out = Out0 def apply(): Out = annotations } - - implicit def materialize[T, Out <: HList]: Aux[T, Out] = macro AnnotationMacros.materializeAllTypeAnnotations[T, Out] -} - -class AnnotationMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def optionTpe: Type = typeOf[Option[_]].typeConstructor - def someTpe: Type = typeOf[Some[_]].typeConstructor - def noneTpe: Type = typeOf[None.type] - - /** - * FIXME Most of the content of this method is cut-n-pasted from generic.scala - * - * @return The AST of the `tpe` constructor. - */ - def construct(tpe: Type): List[Tree] => Tree = { - // FIXME Cut-n-pasted from generic.scala - val sym = tpe.typeSymbol - val isCaseClass = sym.asClass.isCaseClass - def hasNonGenericCompanionMember(name: String): Boolean = { - val mSym = sym.companion.typeSignature.member(TermName(name)) - mSym != NoSymbol && !isNonGeneric(mSym) - } - - if(isCaseClass || hasNonGenericCompanionMember("apply")) - args => q"${companionRef(tpe)}(..$args)" - else - args => q"new $tpe(..$args)" - } - - def materializeAnnotation[A: WeakTypeTag, T: WeakTypeTag]: Option[Tree] = { - val annTpe = weakTypeOf[A] - - if (!isProduct(annTpe)) - abort(s"$annTpe is not a case class-like type") - - val construct0 = construct(annTpe) - - val tpe = weakTypeOf[T] - - tpe.typeSymbol.annotations.collectFirst { - case ann if ann.tree.tpe =:= annTpe => construct0(ann.tree.children.tail) - } - } - - def materializeAnnotationRequired[A: WeakTypeTag, T: WeakTypeTag]: Tree = { - val annTpe = weakTypeOf[A] - val tpe = weakTypeOf[T] - - materializeAnnotation[A, T] match { - case Some(annTree) => - q"_root_.shapeless.Annotation.mkAnnotation[$annTpe, $tpe]($annTree)" - case None => - abort(s"No $annTpe annotation found on $tpe") - } - } - - def materializeAnnotationOptional[A: WeakTypeTag, T: WeakTypeTag]: Tree = { - val optAnnTpe = appliedType(optionTpe, weakTypeOf[A]) - val tpe = weakTypeOf[T] - - materializeAnnotation[A, T] match { - case Some(annTree) => - q"_root_.shapeless.Annotation.mkAnnotation[$optAnnTpe, $tpe](_root_.scala.Some($annTree))" - case None => - q"_root_.shapeless.Annotation.mkAnnotation[$optAnnTpe, $tpe](_root_.scala.None)" - } - } - - def materializeVariableAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag]: Tree = - materializeAnnotations[A, T, Out](typeAnnotation = false) - - def materializeAllVariableAnnotations[T: WeakTypeTag, Out: WeakTypeTag]: Tree = - materializeAllAnnotations[T, Out](typeAnnotation = false) - - def materializeTypeAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag]: Tree = - materializeAnnotations[A, T, Out](typeAnnotation = true) - - def materializeAllTypeAnnotations[T: WeakTypeTag, Out: WeakTypeTag]: Tree = - materializeAllAnnotations[T, Out](typeAnnotation = true) - - def materializeAnnotations[A: WeakTypeTag, T: WeakTypeTag, Out: WeakTypeTag](typeAnnotation: Boolean): Tree = { - val annTpe = weakTypeOf[A] - - if (!isProduct(annTpe)) - abort(s"$annTpe is not a case class-like type") - - val tpe = weakTypeOf[T] - - val annTreeOpts = getAnnotationTreeOptions(tpe, typeAnnotation).map { list => - list.find(_._1 =:= annTpe).map(_._2) - } - - val wrapTpeTrees = annTreeOpts.map { - case Some(annTree) => appliedType(someTpe, annTpe) -> q"_root_.scala.Some($annTree)" - case None => noneTpe -> q"_root_.scala.None" - } - - val outTpe = mkHListTpe(wrapTpeTrees.map { case (aTpe, _) => aTpe }) - val outTree = wrapTpeTrees.foldRight(q"_root_.shapeless.HNil": Tree) { - case ((_, bound), acc) => pq"_root_.shapeless.::($bound, $acc)" - } - - if (typeAnnotation) q"_root_.shapeless.TypeAnnotations.mkAnnotations[$annTpe, $tpe, $outTpe]($outTree)" - else q"_root_.shapeless.Annotations.mkAnnotations[$annTpe, $tpe, $outTpe]($outTree)" - } - - def materializeAllAnnotations[T: WeakTypeTag, Out: WeakTypeTag](typeAnnotation: Boolean): Tree = { - val tpe = weakTypeOf[T] - val annTreeOpts = getAnnotationTreeOptions(tpe, typeAnnotation) - - val wrapTpeTrees = annTreeOpts.map { - case Nil => - mkHListTpe(Nil) -> q"(_root_.shapeless.HNil)" - case list => - mkHListTpe(list.map(_._1)) -> list.foldRight(q"_root_.shapeless.HNil": Tree) { - case ((_, bound), acc) => pq"_root_.shapeless.::($bound, $acc)" - } - } - - val outTpe = mkHListTpe(wrapTpeTrees.map { case (aTpe, _) => aTpe }) - val outTree = wrapTpeTrees.foldRight(q"_root_.shapeless.HNil": Tree) { - case ((_, bound), acc) => - pq"_root_.shapeless.::($bound, $acc)" - } - - if (typeAnnotation) q"_root_.shapeless.AllTypeAnnotations.mkAnnotations[$tpe, $outTpe]($outTree)" - else q"_root_.shapeless.AllAnnotations.mkAnnotations[$tpe, $outTpe]($outTree)" - } - - def getAnnotationTreeOptions(tpe: Type, typeAnnotation: Boolean): List[List[(Type, Tree)]] = { - if (isProduct(tpe)) { - val constructorSyms = tpe - .member(termNames.CONSTRUCTOR) - .asMethod - .paramLists - .flatten - .map(sym => nameAsString(sym.name) -> sym) - .toMap - - fieldsOf(tpe).map { - case (name, _) => - extract(typeAnnotation, constructorSyms(nameAsString(name))).collect { - case ann if isProduct(ann.tree.tpe) => - val construct1 = construct(ann.tree.tpe) - (ann.tree.tpe, construct1(ann.tree.children.tail)) - } - } - } else if (isCoproduct(tpe)) { - ctorsOf(tpe).map { cTpe => - extract(typeAnnotation, cTpe.typeSymbol).collect { - case ann if isProduct(ann.tree.tpe) => - val construct1 = construct(ann.tree.tpe) - (ann.tree.tpe, construct1(ann.tree.children.tail)) - } - } - } else { - abort(s"$tpe is not case class like or the root of a sealed family of types") - } - } - - def extract(tpe: Boolean, s: Symbol): List[c.universe.Annotation] = { - def fromType(t: Type): List[c.universe.Annotation] = t match { - case AnnotatedType(annotations, _) => annotations.reverse - case ClassInfoType(parents, _, _) => parents.flatMap(fromType) - case TypeRef(_, sym, _) if sym.asType.isAliasType => extract(tpe, sym) - case _ => Nil - } - - if (tpe) fromType(s.typeSignature) - else s.annotations - } - } diff --git a/core/src/main/scala/shapeless/conversions.scala b/core/src/main/scala/shapeless/conversions.scala index 71f299348..14f4c2e07 100644 --- a/core/src/main/scala/shapeless/conversions.scala +++ b/core/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/src/main/scala/shapeless/coproduct.scala b/core/src/main/scala/shapeless/coproduct.scala index 94929dd3e..1307c4e5d 100644 --- a/core/src/main/scala/shapeless/coproduct.scala +++ b/core/src/main/scala/shapeless/coproduct.scala @@ -17,7 +17,6 @@ package shapeless import scala.language.dynamics -import scala.language.experimental.macros import scala.annotation.tailrec @@ -119,7 +118,7 @@ sealed trait CNil extends Coproduct { def impossible: Nothing } -object Coproduct extends Dynamic { +object Coproduct extends Dynamic with CoproductScalaCompat { import ops.coproduct.Inject import ops.coproduct.RuntimeInject import syntax.CoproductOps @@ -130,7 +129,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)) @@ -139,25 +138,9 @@ object Coproduct extends Dynamic { def unsafeGet(c: Coproduct): Any = c match { case Inl(h) => h case Inr(c) => unsafeGet(c) + case nil: CNil => nil.impossible } - - /** - * Allows to specify a `Coproduct` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = Coproduct.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = Coproduct.`'a, 'b, 'c`.T - * type TwoTrueStr = Coproduct.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.coproductType - /** Allows to inject a runtime value of type `Any` in a `Coproduct` */ def runtimeInject[C <: Coproduct](x: Any)(implicit rinj: RuntimeInject[C]): Option[C] = rinj(x) } diff --git a/core/src/main/scala/shapeless/default.scala b/core/src/main/scala/shapeless/default.scala index 0d06b3c4b..ea1efaf41 100644 --- a/core/src/main/scala/shapeless/default.scala +++ b/core/src/main/scala/shapeless/default.scala @@ -1,8 +1,5 @@ package shapeless -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - import shapeless.labelled.{ FieldType, field } /** @@ -36,7 +33,7 @@ trait Default[T] extends DepFn0 with Serializable { type Out <: HList } -object Default { +object Default extends DefaultScalaCompat { def apply[T](implicit default: Default[T]): Aux[T, default.Out] = default def mkDefaultByName[T, Out0 <: HList](defaults: => Out0): Aux[T, Out0] = @@ -47,8 +44,6 @@ object Default { type Aux[T, Out0 <: HList] = Default[T] { type Out = Out0 } - implicit def materialize[T, L <: HList]: Aux[T, L] = macro DefaultMacros.materialize[T, L] - /** * Provides default values of case class-like types, as a record. @@ -204,82 +199,3 @@ object Default { } } } - -class DefaultMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def someTpe = typeOf[Some[_]].typeConstructor - def noneTpe = typeOf[None.type] - - def materialize[T: WeakTypeTag, L: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T] - val cls = classSym(tpe) - - lazy val companion = companionRef(tpe) - def altCompanion = companion.symbol.info - - val none = q"_root_.scala.None" - def some(value: Tree) = q"_root_.scala.Some($value)" - - // Symbol.alternatives is missing in Scala 2.10 - def overloadsOf(sym: Symbol) = - if (sym.isTerm) sym.asTerm.alternatives - else if (sym.isType) sym :: Nil - else Nil - - def hasDefaultParams(method: MethodSymbol) = - method.paramLists.flatten.exists(_.asTerm.isParamWithDefault) - - // The existence of multiple apply overloads with default values gets checked - // after the macro runs. Their existence can make the macro expansion fail, - // as multiple overloads can define the functions we look for below, possibly - // with wrong types, making the compilation fail with the wrong error. - // We do this check here to detect that beforehand. - def overloadsWithDefaultParamsIn(tpe: Type) = - overloadsOf(tpe.member(TermName("apply"))).count { - alt => alt.isMethod && hasDefaultParams(alt.asMethod) - } - - def defaultsFor(fields: List[(TermName, Type)]) = for { - ((_, argTpe), i) <- fields.zipWithIndex - default = tpe.companion.member(TermName(s"apply$$default$$${i + 1}")) orElse - altCompanion.member(TermName(s"$$lessinit$$greater$$default$$${i + 1}")) - } yield if (default.isTerm) { - val defaultTpe = appliedType(someTpe, devarargify(argTpe)) - val defaultVal = some(q"$companion.$default") - (defaultTpe, defaultVal) - } else (noneTpe, none) - - def mkDefault(defaults: List[(Type, Tree)]) = { - val (types, values) = defaults.unzip - val outTpe = mkHListTpe(types) - val outVal = mkHListValue(values) - q"_root_.shapeless.Default.mkDefaultByName[$tpe, $outTpe]($outVal)" - } - - if (isCaseObjectLike(cls)) return mkDefault(Nil) - if (!isCaseClassLike(cls)) abort(s"$tpe is not a case class or case class like") - - // ClassSymbol.primaryConstructor is missing in Scala 2.10 - val primaryCtor = overloadsOf(tpe.decl(termNames.CONSTRUCTOR)).find { - alt => alt.isMethod && alt.asMethod.isPrimaryConstructor - }.getOrElse { - c.abort(c.enclosingPosition, s"Cannot get primary constructor of $tpe") - }.asMethod - - // Checking if the primary constructor has default parameters, and returning - // a Default instance with non-empty types / values only if that holds. - // The apply$default$... methods below may still exist without these, if an additional - // apply method has default parameters. We want to ignore them in this case. - val hasUniqueDefaults = hasDefaultParams(primaryCtor) && { - val k = overloadsWithDefaultParamsIn(tpe.companion) - k == 1 || (k == 0 && overloadsWithDefaultParamsIn(altCompanion) == 1) - } - - mkDefault { - val fields = fieldsOf(tpe) - if (hasUniqueDefaults) defaultsFor(fields) - else List.fill(fields.size)((noneTpe, none)) - } - } -} diff --git a/core/src/main/scala/shapeless/generic.scala b/core/src/main/scala/shapeless/generic.scala index 730e43e4d..1cba8da25 100644 --- a/core/src/main/scala/shapeless/generic.scala +++ b/core/src/main/scala/shapeless/generic.scala @@ -16,9 +16,7 @@ package shapeless -import scala.annotation.{StaticAnnotation, tailrec} -import scala.language.experimental.macros -import scala.reflect.macros.{blackbox, whitebox} +import scala.annotation.StaticAnnotation /** Represents the ability to convert from a concrete type (e.g. a case class) * to a generic ([[HList]] / [[Coproduct]]} based) representation of the type. @@ -112,7 +110,7 @@ trait Generic[T] extends Serializable { * for some T. In addition, it defines [[Generic.Aux]], which is an important implementation technique * that can be generally useful. */ -object Generic { +object Generic extends GenericScalaCompat { /** Provides a representation of Generic[T], which has a nested Repr type, as a type with two type * parameters instead. @@ -161,8 +159,6 @@ object Generic { def to(t: T): R = f(t) def from(r: R): T = g(r) } - - implicit def materialize[T, R]: Aux[T, R] = macro GenericMacros.materialize[T, R] } /** @@ -210,7 +206,7 @@ trait LabelledGeneric[T] extends Serializable { def from(r : Repr) : T } -object LabelledGeneric { +object LabelledGeneric extends LabelledGenericScalaCompat { /** Like [[shapeless.Generic.Aux]], this is an implementation of the Aux pattern, please * see comments there. @@ -228,790 +224,18 @@ object LabelledGeneric { def to(t: T): Repr = gen.to(t).asInstanceOf[R] def from(r: Repr): T = gen.from(r.asInstanceOf[gen.Repr]) } - - implicit def materialize[T, R]: Aux[T, R] = - macro LabelledMacros.mkLabelledGeneric[T, R] } class nonGeneric extends StaticAnnotation class IsTuple[T] extends Serializable -object IsTuple { - implicit def apply[T]: IsTuple[T] = macro GenericMacros.mkIsTuple[T] -} +object IsTuple extends IsTupleScalaCompat class HasProductGeneric[T] extends Serializable -object HasProductGeneric { - implicit def apply[T]: HasProductGeneric[T] = macro GenericMacros.mkHasProductGeneric[T] -} +object HasProductGeneric extends HasProductGenericScalaCompat class HasCoproductGeneric[T] extends Serializable -object HasCoproductGeneric { - implicit def apply[T]: HasCoproductGeneric[T] = macro GenericMacros.mkHasCoproductGeneric[T] -} - -trait ReprTypes { - val c: blackbox.Context - import c.universe.{Symbol => _, _} - - def hlistTpe = typeOf[HList] - def hnilTpe = typeOf[HNil] - def hconsTpe = typeOf[::[_, _]].typeConstructor - def coproductTpe = typeOf[Coproduct] - def cnilTpe = typeOf[CNil] - def cconsTpe = typeOf[:+:[_, _]].typeConstructor - - def atatTpe = typeOf[tag.@@[_,_]].typeConstructor - def fieldTypeTpe = typeOf[shapeless.labelled.FieldType[_, _]].typeConstructor - def keyTagTpe = typeOf[shapeless.labelled.KeyTag[_, _]].typeConstructor - def symbolTpe = typeOf[Symbol] - - def objectRef[O: TypeTag]: Tree = Ident(typeOf[O].termSymbol) -} - -trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { - val c: blackbox.Context - - import c.universe._ - - def abort(msg: String): Nothing = - c.abort(c.enclosingPosition, msg) - - def isReprType(tpe: Type): Boolean = - tpe <:< hlistTpe || tpe <:< coproductTpe - - def isReprType1(tpe: Type): Boolean = - isReprType(lowerKind(tpe)) - - /** - * Lower the order of `tpe`'s kind by applying `Any` in place of all type parameters (`Any` is poly-kinded). - * Note that the resulting type is dealiased before being returned. - * - * {{{ - * lowerKind(typeOf[List[_]].typeConstructor) -> List[Any] - * }}} - */ - def lowerKind(tpe: Type): Type = - appliedType(tpe, tpe.typeParams.map(_ => definitions.AnyTpe)).dealias - - def isProductAux(tpe: Type): Boolean = - tpe.typeSymbol.isClass && { - val cls = classSym(tpe) - isCaseObjectLike(cls) || isCaseClassLike(cls) || HasApplyUnapply(tpe) || HasCtorUnapply(tpe) - } - - def isProduct(tpe: Type): Boolean = - tpe =:= definitions.UnitTpe || (!(tpe =:= definitions.AnyRefTpe) && isProductAux(tpe)) - - def isProduct1(tpe: Type): Boolean = - isProduct(lowerKind(tpe)) - - def isCoproduct(tpe: Type): Boolean = - tpe.typeSymbol.isClass && { - val cls = classSym(tpe) - (cls.isTrait || cls.isAbstract) && cls.isSealed - } - - def ownerChain(sym: Symbol): List[Symbol] = { - @tailrec - def loop(sym: Symbol, acc: List[Symbol]): List[Symbol] = - if(sym.owner == NoSymbol) acc - else loop(sym.owner, sym :: acc) - - loop(sym, Nil) - } - - def isAnonOrRefinement(sym: Symbol): Boolean = { - val nameStr = sym.name.toString - nameStr.contains("$anon") || nameStr == "" - } - - /** - * @return a List of name and type pairs for the fields of type `tpe`. - * @see [[isCaseAccessorLike]] for the definition of what is considered a field. - * */ - def fieldsOf(tpe: Type): List[(TermName, Type)] = { - val clazz = tpe.typeSymbol.asClass - val isCaseClass = clazz.isCaseClass - if (isCaseObjectLike(clazz) || isAnonOrRefinement(clazz)) Nil - else tpe.decls.sorted.collect { - case sym: TermSymbol if isCaseAccessorLike(sym, isCaseClass) => - (sym.name, sym.typeSignatureIn(tpe).finalResultType) - } - } - - def productCtorsOf(tpe: Type): List[Symbol] = tpe.decls.toList.filter(_.isConstructor) - - def accessiblePrimaryCtorOf(tpe: Type): Option[Symbol] = { - for { - ctor <- tpe.decls.find { sym => sym.isMethod && sym.asMethod.isPrimaryConstructor && isAccessible(tpe, sym) } - if !ctor.isJava || productCtorsOf(tpe).size == 1 - } yield ctor - } - - def ctorsOf(tpe: Type): List[Type] = distinctCtorsOfAux(tpe, hk = false) - def ctorsOf1(tpe: Type): List[Type] = distinctCtorsOfAux(tpe, hk = true) - - def distinctCtorsOfAux(tpe: Type, hk: Boolean): List[Type] = { - def distinct[A](list: List[A])(eq: (A, A) => Boolean): List[A] = list.foldLeft(List.empty[A]) { (acc, x) => - if (!acc.exists(eq(x, _))) x :: acc - else acc - }.reverse - distinct(ctorsOfAux(tpe, hk))(_ =:= _) - } - - def ctorsOfAux(tpe: Type, hk: Boolean): List[Type] = { - def collectCtors(classSym: ClassSymbol): List[ClassSymbol] = { - classSym.knownDirectSubclasses.toList flatMap { child0 => - val child = child0.asClass - child.typeSignature // Workaround for - if (isCaseClassLike(child) || isCaseObjectLike(child)) - List(child) - else if (child.isSealed) - collectCtors(child) - else - abort(s"$child is not case class like or a sealed trait") - } - } - - if(isProduct(tpe)) - List(tpe) - else if(isCoproduct(tpe)) { - val basePre = prefix(tpe) - val baseSym = classSym(tpe) - val baseTpe = - if(!hk) tpe - else { - val tc = tpe.typeConstructor - val paramSym = tc.typeParams.head - val paramTpe = paramSym.asType.toType - appliedType(tc, paramTpe) - } - val baseArgs = baseTpe.dealias.typeArgs - - def isLess(sym1: Symbol, sym2: Symbol): Boolean = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gSym1 = sym1.asInstanceOf[global.Symbol] - val gSym2 = sym2.asInstanceOf[global.Symbol] - gSym1.isLess(gSym2) - } - - def orderSyms(s1: Symbol, s2: Symbol): Boolean = { - val fn1 = s1.fullName - val fn2 = s2.fullName - fn1 < fn2 || (fn1 == fn2 && isLess(s1, s2)) - } - - val ctors = collectCtors(baseSym).sortWith(orderSyms).flatMap { sym => - import c.internal._ - - val owner = sym.owner - val isNamed = !isAnonOrRefinement(sym) - - // Construct a stable prefix from the path. - val pre = if (sym.isStatic) prefix(sym.toType) else { - // Look for a path from the macro call site to the subtype. - val owners = ownerChain(if (isNamed) owner else owner.owner) - val prePaths = for (pre <- Iterator.iterate(basePre)(prefix).takeWhile(_ != NoPrefix)) - yield (pre, owners.iterator.dropWhile(pre.baseType(_) == NoType)) - - // Find a path from a (sub-)prefix or the enclosing owner. - val (pre0, path) = prePaths.find(_._2.nonEmpty).getOrElse { - val enclosing = ownerChain(enclosingOwner) - val common = owners zip enclosing indexWhere { case (o1, o2) => o1 != o2 } - (NoPrefix, if (common < 0) Iterator.empty else owners.iterator drop common - 1) - } - - path.drop(1).foldLeft(pre0) { (pre1, part) => - if (part.isType) part.asType.toTypeIn(pre1) - else abort(s"$tpe has a subtype $sym with unstable prefix") - } - } - - val ctor = if (isNamed) { - if (sym.isModuleClass) { - singleType(pre, sym.module) - } else { - val subst = thisType(sym).baseType(baseSym).typeArgs.map(_.typeSymbol) - val params = sym.typeParams - val free = params.exists(!subst.contains(_)) - val args = for (param <- params) yield { - val i = subst.indexOf(param) - if (i >= 0) baseArgs(i) else param.asType.toType - } - - val ref = typeRef(pre, sym, args) - if (free) existentialAbstraction(params, ref) else ref - } - } else { - def ownerIsSubType = owner.typeSignatureIn(pre) <:< baseTpe - if (owner.isTerm && owner.asTerm.isVal && ownerIsSubType) singleType(pre, owner) - else abort(s"$tpe has a subtype $sym with unstable prefix") - } - - if (!isAccessible(ctor)) abort(s"$tpe has an inaccessible subtype $ctor") - else if (ctor <:< baseTpe) Some(ctor) - else None - } - - if (ctors.isEmpty) abort(s"Sealed trait $tpe has no case class subtypes") - else ctors - } else { - abort(s"$tpe is not a case class, case class-like, a sealed trait or Unit") - } - } - - def nameAsString(name: Name): String = - name.decodedName.toString.trim - - def nameAsValue(name: Name): Constant = - Constant(nameAsString(name)) - - def nameOf(tpe: Type): Name = - tpe.typeSymbol.name - - def mkHListValue(elems: List[Tree]): Tree = - elems.foldRight(q"_root_.shapeless.HNil": Tree) { - case (elem, acc) => q"_root_.shapeless.::($elem, $acc)" - } - - /** - * Fold `items` into a type using `cons` as a type constructor. - * - * {{{ - * mkCompoundTpe(hnilTpe, hconsTpe, Seq(typeOf[String], typeOf[Int])) -> String :: Int :: HNil - * }}} - */ - def mkCompoundTpe(nil: Type, cons: Type, items: Seq[Type]): Type = - items.foldRight(nil) { (tpe, acc) => - appliedType(cons, List(devarargify(tpe), acc)) - } - - /** - * Convert `items` to corresponding HList type. - */ - def mkHListTpe(items: Seq[Type]): Type = - mkCompoundTpe(hnilTpe, hconsTpe, items) - - /** - * Convert `items` to corresponding Coproduct type. - */ - def mkCoproductTpe(items: Seq[Type]): Type = - mkCompoundTpe(cnilTpe, cconsTpe, items) - - def unpackHList(tpe: Type): Vector[Type] = - unpackReprType(tpe, hnilTpe, hconsTpe) - - def unpackCoproduct(tpe: Type): Vector[Type] = - unpackReprType(tpe, cnilTpe, cconsTpe) - - def unpackReprType(tpe: Type, nil: Type, cons: Type): Vector[Type] = { - val consSym = cons.typeSymbol - @tailrec def unpack(tpe: Type, acc: Vector[Type]): Vector[Type] = - if (tpe <:< nil) acc else tpe.baseType(consSym) match { - case TypeRef(_, _, List(head, tail)) => unpack(tail, acc :+ head) - case _ => abort(s"$tpe is not an HList or Coproduct type") - } - - unpack(tpe, Vector.empty) - } - - object FieldType { - import internal._ - - private val KeyTagSym = keyTagTpe.typeSymbol - - def apply(key: Type, value: Type): Type = - appliedType(fieldTypeTpe, key, value) - - def unapply(field: Type): Option[(Type, Type)] = field.dealias match { - case RefinedType(List(value, TypeRef(_, KeyTagSym, List(key, _))), scope) - if scope.isEmpty => Some(key -> value) - case RefinedType(parents :+ TypeRef(_, KeyTagSym, List(key, value)), scope) - if value =:= refinedType(parents, scope) => Some(key -> value) - case _ => - None - } - } - - def findField(record: Type, key: Type): Option[(Type, Type, Int)] = - findField(unpackHList(record), key) - - def findField(fields: Seq[Type], key: Type): Option[(Type, Type, Int)] = - fields.iterator.zipWithIndex.collectFirst { - case (FieldType(k, v), i) if k =:= key => (k, v, i) - } - - def appliedTypTree1(tpe: Type, param: Type, arg: TypeName): Tree = { - tpe match { - case t if t =:= param => - Ident(arg) - case PolyType(params, body) if params.head.asType.toType =:= param => - appliedTypTree1(body, param, arg) - case TypeRef(pre, sym, Nil) => - mkAttributedRef(pre, sym) - case TypeRef(pre, sym, args) => - val argTrees = args.map(appliedTypTree1(_, param, arg)) - AppliedTypeTree(mkAttributedRef(pre, sym), argTrees) - case other => - tq"$other" - } - } - - def mkCompoundTypTree1(nil: Type, cons: Type, items: List[Type], param: Type, arg: TypeName): Tree = - items.foldRight(mkAttributedRef(nil): Tree) { case (tpe, acc) => - AppliedTypeTree(mkAttributedRef(cons), List(appliedTypTree1(tpe, param, arg), acc)) - } - - def mkHListTypTree1(items: List[Type], param: Type, arg: TypeName): Tree = - mkCompoundTypTree1(hnilTpe, hconsTpe, items, param, arg) - - def mkCoproductTypTree1(items: List[Type], param: Type, arg: TypeName): Tree = - mkCompoundTypTree1(cnilTpe, cconsTpe, items, param, arg) - - def param1(tpe: Type): Type = - tpe match { - case t if tpe.takesTypeArgs => t.typeParams.head.asType.toType - case TypeRef(_, _, List(arg)) => arg - case _ => NoType - } - - def reprTypTree1(tpe: Type, arg: TypeName): Tree = { - val param = param1(tpe) - if(isProduct1(tpe)) mkHListTypTree1(fieldsOf(tpe).map(_._2), param, arg) - else mkCoproductTypTree1(ctorsOf1(tpe), param, arg) - } - - def isCaseClassLike(sym: ClassSymbol): Boolean = { - def isConcrete = !(sym.isAbstract || sym.isTrait || sym == symbolOf[Object]) - def isFinalLike = sym.isFinal || sym.knownDirectSubclasses.isEmpty - def ctor = for { - ctor <- accessiblePrimaryCtorOf(sym.typeSignature) - Seq(params) <- Option(ctor.typeSignature.paramLists) - if params.size == fieldsOf(sym.typeSignature).size - } yield ctor - sym.isCaseClass || (isConcrete && isFinalLike && ctor.isDefined) - } - - def isCaseObjectLike(sym: ClassSymbol): Boolean = sym.isModuleClass - - def isCaseAccessorLike(sym: TermSymbol, inCaseClass: Boolean): Boolean = { - val isGetter = - if (inCaseClass) sym.isCaseAccessor && !sym.isMethod - else sym.isGetter && sym.isPublic && (sym.isParamAccessor || sym.isLazy) - isGetter && !isNonGeneric(sym) - } - - def classSym(tpe: Type): ClassSymbol = { - val sym = tpe.typeSymbol - if (!sym.isClass) - abort(s"$sym is not a class or trait") - - val classSym = sym.asClass - classSym.typeSignature // Workaround for - - classSym - } - - // See https://github.com/milessabin/shapeless/issues/212 - def companionRef(tpe: Type): Tree = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gTpe = tpe.asInstanceOf[global.Type] - val pre = gTpe.prefix - val cSym = patchedCompanionSymbolOf(tpe.typeSymbol).asInstanceOf[global.Symbol] - if(cSym != NoSymbol) - global.gen.mkAttributedRef(pre, cSym).asInstanceOf[Tree] - else - Ident(tpe.typeSymbol.name.toTermName) // Attempt to refer to local companion - } - - def isAccessible(pre: Type, sym: Symbol): Boolean = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val typer = c.asInstanceOf[scala.reflect.macros.runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer] - val typerContext = typer.context - typerContext.isAccessible( - sym.asInstanceOf[global.Symbol], - pre.asInstanceOf[global.Type] - ) - } - def isAccessible(tpe: Type): Boolean = - isAccessible(prefix(tpe), tpe.typeSymbol) - - // 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: Symbol): 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 prefix(tpe: Type): Type = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gTpe = tpe.asInstanceOf[global.Type] - gTpe.prefix.asInstanceOf[Type] - } - - def mkAttributedRef(tpe: Type): Tree = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gTpe = tpe.asInstanceOf[global.Type] - val pre = gTpe.prefix - val sym = gTpe.typeSymbol - global.gen.mkAttributedRef(pre, sym).asInstanceOf[Tree] - } - - def mkAttributedRef(pre: Type, sym: Symbol): Tree = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gPre = pre.asInstanceOf[global.Type] - val gSym = sym.asInstanceOf[global.Symbol] - global.gen.mkAttributedRef(gPre, gSym).asInstanceOf[Tree] - } - - def mkAttributedRef(singleton: SingleType): Tree = { - val SingleType(pre, sym) = (singleton: @unchecked) - val getter = sym.asTerm.getter.orElse(sym) - mkAttributedRef(pre, getter) - } - - /** - * Check if `sym` or any of its overrides are annotated by [[nonGeneric]]. - */ - def isNonGeneric(sym: Symbol): Boolean = { - def check(sym: Symbol): Boolean = { - // See https://issues.scala-lang.org/browse/SI-7424 - sym.typeSignature // force loading method's signature - sym.annotations.foreach(_.tree.tpe) // force loading all the annotations - - sym.annotations.exists(_.tree.tpe =:= typeOf[nonGeneric]) - } - - // See https://issues.scala-lang.org/browse/SI-7561 - check(sym) || - (sym.isTerm && sym.asTerm.isAccessor && check(sym.asTerm.accessed)) || - sym.overrides.exists(isNonGeneric) - } - - def isTuple(tpe: Type): Boolean = - tpe <:< typeOf[Unit] || definitions.TupleClass.seq.contains(tpe.typeSymbol) - - def isVararg(tpe: Type): Boolean = - tpe.typeSymbol == c.universe.definitions.RepeatedParamClass - - /** - * Convert a varargs type to corresponding Seq type. - * - * {{{ - * String* -> Seq[String] - * }}} - */ - def devarargify(tpe: Type): Type = - tpe match { - case TypeRef(_, _, args) if isVararg(tpe) => - appliedType(varargTC, args) - case _ => tpe - } - - def unByName(tpe: Type): Type = - tpe match { - case TypeRef(_, sym, List(tpe)) if sym == definitions.ByNameParamClass => tpe - case tpe => tpe - } - - def equalTypes(as: List[Type], bs: List[Type]): Boolean = - as.length == bs.length && (as zip bs).foldLeft(true) { case (acc, (a, b)) => acc && unByName(a) =:= unByName(b) } - - def alignFields(tpe: Type, args: List[(TermName, Type)]): Option[List[(TermName, Type)]] = for { - fields <- Option(fieldsOf(tpe)) - if fields.size == args.size - if fields.zip(args).forall { case ((fn, ft), (an, at)) => - (fn == an || at.typeSymbol == definitions.ByNameParamClass) && ft =:= unByName(at) - } - } yield fields - - def numNonCaseParamLists(tpe: Type): Int = { - val companion = patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature - val apply = companion.member(TermName("apply")) - if (apply.isMethod && !isNonGeneric(apply) && isAccessible(companion, apply)) { - val paramLists = apply.typeSignatureIn(companion).paramLists - val numParamLists = paramLists.length - if (numParamLists <= 1) 0 - else { - if (paramLists.last.headOption.exists(_.isImplicit)) - numParamLists-2 - else - numParamLists-1 - } - } else 0 - } - - object HasApply { - def unapply(tpe: Type): Option[List[(TermName, Type)]] = for { - companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature) - apply = companion.member(TermName("apply")) - if apply.isMethod && !isNonGeneric(apply) - if isAccessible(companion, apply) - Seq(params) <- Option(apply.typeSignatureIn(companion).paramLists) - aligned <- alignFields(tpe, for (param <- params) - yield param.name.toTermName -> param.typeSignature) - } yield aligned - } - - object HasUnapply { - def unapply(tpe: Type): Option[List[Type]] = for { - companion <- Option(patchedCompanionSymbolOf(tpe.typeSymbol).typeSignature) - unapply = companion.member(TermName("unapply")) - if unapply.isMethod && !isNonGeneric(unapply) - if isAccessible(companion, unapply) - returnTpe <- unapply.asMethod.typeSignatureIn(companion).finalResultType - .baseType(symbolOf[Option[_]]).typeArgs.headOption - } yield if (returnTpe <:< typeOf[Product]) returnTpe.typeArgs else List(returnTpe) - } - - object HasUniqueCtor { - def unapply(tpe: Type): Option[List[(TermName, Type)]] = for { - ctor <- accessiblePrimaryCtorOf(tpe) - if !isNonGeneric(ctor) - Seq(params) <- Option(ctor.typeSignatureIn(tpe).paramLists) - aligned <- alignFields(tpe, for (param <- params) - yield param.name.toTermName -> param.typeSignature) - } yield aligned - } - - object HasApplyUnapply { - def apply(tpe: Type): Boolean = unapply(tpe).isDefined - def unapply(tpe: Type): Option[List[(TermName, Type)]] = - (tpe, tpe) match { - case (HasApply(as), HasUnapply(bs)) if equalTypes(as.map(_._2), bs) => Some(as) - case _ => None - } - } - - object HasCtorUnapply { - def apply(tpe: Type): Boolean = unapply(tpe).isDefined - def unapply(tpe: Type): Option[List[(TermName, Type)]] = - (tpe, tpe) match { - case(HasUniqueCtor(as), HasUnapply(bs)) if equalTypes(as.map(_._2), bs) => Some(as) - case _ => None - } - } - - trait CtorDtor { - def construct(args: List[Tree]): Tree - def binding: (Tree, List[Tree]) - def reprBinding: (Tree, List[Tree]) - } - - object CtorDtor { - def apply(tpe: Type): CtorDtor = { - val sym = tpe.typeSymbol - val isCaseClass = sym.asClass.isCaseClass - - val repWCard = Star(Ident(termNames.WILDCARD)) // like pq"_*" except that it does work - - def narrow(tree: Tree, tpe: Type): Tree = - tpe match { - case ConstantType(c) => - q"$c.asInstanceOf[$tpe]" - case _ => - tree - } - - def narrow1(tree: Tree, tpe: Type): Tree = - if(isVararg(tpe)) - q"$tree: _*" - else - narrow(tree, tpe) - - def mkCtorDtor0(elems0: List[(TermName, Type)]) = { - val elems = elems0.map { case (_, tpe) => (TermName(c.freshName("pat")), tpe) } - val pattern = pq"${companionRef(tpe)}(..${elems.map { case (binder, tpe) => if(isVararg(tpe)) pq"$binder @ $repWCard" else pq"$binder"}})" - val reprPattern = - elems.foldRight(q"_root_.shapeless.HNil": Tree) { - case ((bound, _), acc) => pq"_root_.shapeless.::($bound, $acc)" - } - val nonCaseParamLists: List[List[Tree]] = List.fill(numNonCaseParamLists(tpe))(Nil) - new CtorDtor { - def construct(args: List[Tree]): Tree = q"${companionRef(tpe)}(...${args :: nonCaseParamLists})" - def binding: (Tree, List[Tree]) = (pattern, elems.map { case (binder, tpe) => narrow(q"$binder", tpe) }) - def reprBinding: (Tree, List[Tree]) = (reprPattern, elems.map { case (binder, tpe) => narrow1(q"$binder", tpe) }) - } - } - - def mkCtorDtor1(elems: List[(TermName, TermName, Type)], pattern: Tree, rhs: List[Tree]) = { - val reprPattern = - elems.foldRight(q"_root_.shapeless.HNil": Tree) { - case ((bound, _, _), acc) => pq"_root_.shapeless.::($bound, $acc)" - } - new CtorDtor { - def construct(args: List[Tree]): Tree = q"new $tpe(..$args)" - def binding: (Tree, List[Tree]) = (pattern, rhs) - def reprBinding: (Tree, List[Tree]) = (reprPattern, elems.map { case (binder, _, tpe) => narrow1(q"$binder", tpe) }) - } - } - - lowerKind(tpe) match { - // case 1: Unit - case tpe if tpe =:= typeOf[Unit] => - new CtorDtor { - def construct(args: List[Tree]): Tree = q"()" - def binding: (Tree, List[Tree]) = (pq"()", Nil) - def reprBinding: (Tree, List[Tree]) = (pq"_root_.shapeless.HNil", Nil) - } - - // case 2: singleton - case tpe if isCaseObjectLike(tpe.typeSymbol.asClass) => - val singleton = - tpe match { - case SingleType(pre, sym) => - c.internal.gen.mkAttributedRef(pre, sym) - case TypeRef(pre, sym, List()) if sym.isModule => - c.internal.gen.mkAttributedRef(pre, sym.asModule) - case TypeRef(pre, sym, List()) if sym.isModuleClass => - c.internal.gen.mkAttributedRef(pre, sym.asClass.module) - case _ => - abort(s"Bad case object-like type $tpe") - } - new CtorDtor { - def construct(args: List[Tree]): Tree = q"$singleton: $tpe" - def binding: (Tree, List[Tree]) = (pq"_: $tpe", Nil) - def reprBinding: (Tree, List[Tree]) = (pq"_root_.shapeless.HNil", Nil) - } - - // case 3: case class - case tpe if isCaseClass => mkCtorDtor0(fieldsOf(tpe)) - - // case 4: exactly one matching public apply/unapply - case HasApplyUnapply(args) => mkCtorDtor0(args) - - // case 5: concrete, exactly one public constructor with matching public unapply - case HasCtorUnapply(args) => - val elems = args.map { case (name, tpe) => (TermName(c.freshName("pat")), name, tpe) } - val pattern = pq"${companionRef(tpe)}(..${elems.map { case (binder, _, tpe) => if(isVararg(tpe)) pq"$binder @ $repWCard" else pq"$binder" }})" - val rhs = elems.map { case (binder, _, tpe) => narrow(q"$binder", tpe) } - mkCtorDtor1(elems, pattern, rhs) - - // case 6: concrete, exactly one public constructor with matching accessible fields - case HasUniqueCtor(args) => - val elems = args.map { case (name, tpe) => (TermName(c.freshName("pat")), name, tpe) } - val binder = TermName(c.freshName("pat")) - val pattern = pq"$binder" - val rhs = elems.map { case (_, name, tpe) => narrow(q"$binder.$name", tpe) } - mkCtorDtor1(elems, pattern, rhs) - - case _ => abort(s"Bad product type $tpe") - } - } - } -} - -class GenericMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - private val generic = objectRef[Generic.type] - - def materialize[T: WeakTypeTag, R]: Tree = mkGeneric[T] - - def mkGeneric[T: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T] - if (isReprType(tpe)) - abort("No Generic instance available for HList or Coproduct") - - if (isProduct(tpe)) mkProductGeneric(tpe) - else mkCoproductGeneric(tpe) - } - - def mkProductGeneric(tpe: Type): Tree = { - val repr = mkHListTpe(fieldsOf(tpe).map(_._2)) - val ctorDtor = CtorDtor(tpe) - val (p, ts) = ctorDtor.binding - val to = cq"$p => ${mkHListValue(ts)}.asInstanceOf[$repr]" - val (rp, rts) = ctorDtor.reprBinding - val from = cq"$rp => ${ctorDtor.construct(rts)}.asInstanceOf[$tpe]" - q"$generic.instance[$tpe, $repr]({ case $to }, { case $from })" - } - - def mkCoproductGeneric(tpe: Type): Tree = { - def mkCoproductCases(tpe0: Type, index: Int): Tree = tpe0 match { - case TypeRef(pre, sym, Nil) if sym.isModuleClass => - cq"p if p eq ${mkAttributedRef(pre, sym.asClass.module)} => $index" - case singleton: SingleType => - cq"p if p eq ${mkAttributedRef(singleton)} => $index" - case _ => - cq"_: $tpe0 => $index" - } - - val coproduct = objectRef[Coproduct.type] - val ctors = ctorsOf(tpe) - val repr = mkCoproductTpe(ctors) - val toCases = ctors.zipWithIndex.map((mkCoproductCases _).tupled) - val to = q"$coproduct.unsafeMkCoproduct((p: @_root_.scala.unchecked) match { case ..$toCases }, p).asInstanceOf[$repr]" - q"$generic.instance[$tpe, $repr]((p: $tpe) => $to, $coproduct.unsafeGet(_).asInstanceOf[$tpe])" - } - - def mkIsTuple[T: WeakTypeTag]: Tree = { - val tTpe = weakTypeOf[T] - if (!isTuple(tTpe)) - abort(s"Unable to materialize IsTuple for non-tuple type $tTpe") - - q"new ${weakTypeOf[IsTuple[T]]}" - } - - def mkHasProductGeneric[T: WeakTypeTag]: Tree = { - val tTpe = weakTypeOf[T] - if (isReprType(tTpe) || !isProduct(tTpe)) - abort(s"Unable to materialize HasProductGeneric for $tTpe") - - q"new ${weakTypeOf[HasProductGeneric[T]]}" - } - - def mkHasCoproductGeneric[T: WeakTypeTag]: Tree = { - val tTpe = weakTypeOf[T] - if (isReprType(tTpe) || !isCoproduct(tTpe)) - abort(s"Unable to materialize HasCoproductGeneric for $tTpe") - - q"new ${weakTypeOf[HasCoproductGeneric[T]]}" - } -} +object HasCoproductGeneric extends HasCoproductGenericScalaCompat diff --git a/core/src/main/scala/shapeless/generic1.scala b/core/src/main/scala/shapeless/generic1.scala index cca6be38e..dfac768fc 100644 --- a/core/src/main/scala/shapeless/generic1.scala +++ b/core/src/main/scala/shapeless/generic1.scala @@ -16,9 +16,6 @@ package shapeless -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - trait Generic1[F[_], +FR[_[_]]] extends Serializable { type R[t] @@ -30,15 +27,9 @@ trait Generic1[F[_], +FR[_[_]]] extends Serializable { def mkFrr: FR[R] } -object Generic1 extends Generic10 { +object Generic1 extends Generic10 with Generic1ScalaCompat { type Aux[F[_], +FR[_[_]], R0[_]] = Generic1[F, FR] { type R[t] = R0[t] } - implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] = - macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ] - - implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[U, t] })#λ] = - macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[U, t] })#λ] - def unsafeInstance[F[_], FR[_[_]], R0[_]](f: F[Any] => R0[Any], g: R0[Any] => F[Any])(implicit lazyFr: => FR[R0]): Aux[F, FR, R0] = { new Generic1[F, FR] { type R[t] = R0[t] @@ -49,9 +40,7 @@ object Generic1 extends Generic10 { } } -trait Generic10 { - implicit def apply[T[_], FR[_[_]]]: Generic1[T, FR] = macro Generic1Macros.mkGeneric1Impl[T, FR] -} +trait Generic10 extends Generic10ScalaCompat trait IsHCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { type H[_] @@ -67,21 +56,9 @@ trait IsHCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { def mkFtt: FT[T] } -object IsHCons1 extends IsHCons10 { +object IsHCons1 extends IsHCons10 with IsHCons1ScalaCompat { type Aux[L[_], +FH[_[_]], +FT[_[_]], H0[_], T0[_] <: HList] = IsHCons1[L, FH, FT] { type H[t] = H0[t] ; type T[t] = T0[t] } - implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = - macro IsHCons1Macros.mkIsHCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] - - implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = - macro IsHCons1Macros.mkIsHCons1Impl[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] - - implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = - macro IsHCons1Macros.mkIsHCons1Impl[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] - - implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = - macro IsHCons1Macros.mkIsHCons1Impl[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] - def unsafeInstance[L[_] <: HList, FH[_[_]], FT[_[_]], H0[_], T0[_] <: HList]( f: (H0[Any], T0[Any]) => L[Any], g: L[Any] => (H0[Any], T0[Any]) @@ -98,9 +75,7 @@ object IsHCons1 extends IsHCons10 { } } -trait IsHCons10 { - implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = macro IsHCons1Macros.mkIsHCons1Impl[L, FH, FT] -} +trait IsHCons10 extends IsHCons10ScalaCompat trait IsCCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { type H[_] @@ -116,21 +91,9 @@ trait IsCCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { def mkFtt: FT[T] } -object IsCCons1 extends IsCCons10 { +object IsCCons1 extends IsCCons10 with IsCCons1ScalaCompat { type Aux[L[_], +FH[_[_]], +FT[_[_]], H0[_], T0[_] <: Coproduct] = IsCCons1[L, FH, FT] { type H[t] = H0[t] ; type T[t] = T0[t] } - implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = - macro IsCCons1Macros.mkIsCCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] - - implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = - macro IsCCons1Macros.mkIsCCons1Impl[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] - - implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = - macro IsCCons1Macros.mkIsCCons1Impl[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] - - implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = - macro IsCCons1Macros.mkIsCCons1Impl[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] - def unsafeInstance[L[_] <: Coproduct, FH[_[_]], FT[_[_]], H0[_], T0[_] <: Coproduct]( f: Either[H0[Any], T0[Any]] => L[Any], g: L[Any] => Either[H0[Any], T0[Any]] @@ -147,9 +110,7 @@ object IsCCons1 extends IsCCons10 { } } -trait IsCCons10 { - implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsCCons1[L, FH, FT] = macro IsCCons1Macros.mkIsCCons1Impl[L, FH, FT] -} +trait IsCCons10 extends IsCCons10ScalaCompat trait Split1[L[_], +FO[_[_]], +FI[_[_]]] extends Serializable { type O[_] @@ -165,21 +126,9 @@ trait Split1[L[_], +FO[_[_]], +FI[_[_]]] extends Serializable { def mkFii: FI[I] } -object Split1 extends Split10 { +object Split1 extends Split10 with Split1ScalaCompat { type Aux[L[_], +FO[_[_]], +FI[_[_]], O0[_], I0[_]] = Split1[L, FO, FI] { type O[T] = O0[T] ; type I[T] = I0[T] } - implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] = - macro Split1Macros.mkSplit1Impl[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] - - implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] = - macro Split1Macros.mkSplit1Impl[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] - - implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] = - macro Split1Macros.mkSplit1Impl[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] - - implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] = - macro Split1Macros.mkSplit1Impl[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] - def instance[FO[_[_]], FI[_[_]], O0[_], I0[_]](implicit lazyFoo: => FO[O0], lazyFii: => FI[I0]): Aux[({ type λ[x] = O0[I0[x]] })#λ, FO, FI, O0, I0] = new Split1[({ type λ[x] = O0[I0[x]] })#λ, FO, FI] { type O[x] = O0[x] @@ -191,207 +140,4 @@ object Split1 extends Split10 { } } -trait Split10 { - implicit def apply[L[_], FO[_[_]], FI[_[_]]]: Split1[L, FO, FI] = macro Split1Macros.mkSplit1Impl[L, FO, FI] -} - -class Generic1Macros(val c: whitebox.Context) extends CaseClassMacros { - import c.ImplicitCandidate - import c.universe._ - import definitions._ - - private val generic1 = objectRef[Generic1.type] - - def mkGeneric1Impl[T[_], FR[_[_]]](implicit tTag: WeakTypeTag[T[_]], frTag: WeakTypeTag[FR[Any]]): Tree = { - val tpe = tTag.tpe.etaExpand - val frTpe = c.openImplicits.headOption match { - case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, tpe)), _)) => tpe - case _ => frTag.tpe.typeConstructor - } - - if (isReprType1(tpe)) - abort("No Generic1 instance available for HList or Coproduct") - - if (isProduct1(tpe)) mkProductGeneric1(tpe, frTpe) - else mkCoproductGeneric1(tpe, frTpe) - } - - def mkProductGeneric1(tpe: Type, frTpe: Type): Tree = { - val ctorDtor = CtorDtor(tpe) - val (p, ts) = ctorDtor.binding - val to = cq"$p => ${mkHListValue(ts)}" - val (rp, rts) = ctorDtor.reprBinding - val from = cq"$rp => ${ctorDtor.construct(rts)}" - val name = TypeName(c.freshName("P")) - val reprTpt = reprTypTree1(tpe, name) - val reprName = TypeName(c.freshName("R")) - - q""" - type $reprName[$name] = $reprTpt - $generic1.unsafeInstance[$tpe, $frTpe, $reprName]({ case $to }, { case $from }) - """ - } - - def mkCoproductGeneric1(tpe: Type, frTpe: Type): Tree = { - def mkCoproductCases(tpe: Type, index: Int) = { - val pat = TermName(c.freshName("pat")) - val tc = tpe.typeConstructor - val params = tc.typeParams.map(_ => Bind(typeNames.WILDCARD, EmptyTree)) - val tpt = AppliedTypeTree(mkAttributedRef(tc), params) - cq"$pat: $tpt => $index" - } - - val name = TypeName(c.freshName("C")) - val reprTpt = reprTypTree1(tpe, name) - val reprName = TypeName(c.freshName("R")) - val coproduct = objectRef[Coproduct.type] - val toCases = ctorsOf1(tpe).zipWithIndex.map((mkCoproductCases _).tupled) - val to = q"$coproduct.unsafeMkCoproduct((ft: @_root_.scala.unchecked) match { case ..$toCases }, ft).asInstanceOf[$reprName[$AnyTpe]]" - val from = q"$coproduct.unsafeGet(rt).asInstanceOf[${appliedType(tpe, AnyTpe)}]" - - q""" - type $reprName[$name] = $reprTpt - $generic1.unsafeInstance[$tpe, $frTpe, $reprName](ft => $to, rt => $from) - """ - } -} - -class IsHCons1Macros(val c: whitebox.Context) extends IsCons1Macros { - import c.universe._ - - def mkIsHCons1Impl[L[_], FH[_[_]], FT[_[_]]] - (implicit lTag: WeakTypeTag[L[_]], fhTag: WeakTypeTag[FH[Any]], ftTag: WeakTypeTag[FT[Any]]): Tree = - mkIsCons1(lTag.tpe, fhTag.tpe.typeConstructor, ftTag.tpe.typeConstructor) - - val isCons1TC: Tree = objectRef[IsHCons1.type] - val consTpe: Type = hconsTpe - - def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) = { - val cons = objectRef[::.type] - (q"$cons(_, _)", q"{ case $cons(hd, tl) => (hd, tl) }") - } -} - -class IsCCons1Macros(val c: whitebox.Context) extends IsCons1Macros { - import c.universe._ - import definitions._ - - def mkIsCCons1Impl[L[_], FH[_[_]], FT[_[_]]] - (implicit lTag: WeakTypeTag[L[_]], fhTag: WeakTypeTag[FH[Any]], ftTag: WeakTypeTag[FT[Any]]): Tree = - mkIsCons1(lTag.tpe, fhTag.tpe.typeConstructor, ftTag.tpe.typeConstructor) - - val isCons1TC: Tree = objectRef[IsCCons1.type] - val consTpe: Type = cconsTpe - - def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) = { - val left = objectRef[Left.type] - val right = objectRef[Right.type] - val inl = objectRef[Inl.type] - val inr = objectRef[Inr.type] - - ( - q"""{ - case $left(hd) => $inl(hd: $hdName[$AnyTpe]) - case $right(tl) => $inr(tl: $tlName[$AnyTpe]) - }""", - q"""{ - case $inl(hd) => $left(hd: $hdName[$AnyTpe]) - case $inr(tl) => $right(tl: $tlName[$AnyTpe]) - }""" - ) - } -} - -trait IsCons1Macros extends CaseClassMacros { - val c: whitebox.Context - import c.ImplicitCandidate - import c.internal._ - import c.universe._ - - def isCons1TC: Tree - def consTpe: Type - def mkPackUnpack(hdName: TypeName, tlName: TypeName): (Tree, Tree) - - def mkIsCons1(lTpe: Type, fhTpe0: Type, ftTpe0: Type): Tree = { - val lParam = lTpe.typeParams.head - val lParamTpe = lParam.asType.toType - val lDealiasedTpe = appliedType(lTpe, lParamTpe).dealias - - val (fhTpe, ftTpe) = c.openImplicits.headOption match { - case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, fh, ft)), _)) => (fh, ft) - case _ => (fhTpe0, ftTpe0) - } - - if (!(lDealiasedTpe.typeConstructor =:= consTpe)) - abort("Not H/CCons") - - val TypeRef(_, _, List(hd, tl)) = (lDealiasedTpe: @unchecked) - val hdPoly = polyType(List(lParam), hd) - val tlPoly = polyType(List(lParam), tl) - val name = TypeName(c.freshName()) - val hdTpt = appliedTypTree1(hdPoly, lParamTpe, name) - val tlTpt = appliedTypTree1(tlPoly, lParamTpe, name) - val hdName = TypeName(c.freshName("H")) - val tlName = TypeName(c.freshName("T")) - val (pack, unpack) = mkPackUnpack(hdName, tlName) - - q""" - type $hdName[$name] = $hdTpt - type $tlName[$name] = $tlTpt - $isCons1TC.unsafeInstance[$lTpe, $fhTpe, $ftTpe, $hdName, $tlName]($pack, $unpack) - """ - } -} - -class Split1Macros(val c: whitebox.Context) extends CaseClassMacros { - import c.ImplicitCandidate - import c.internal._ - import c.universe._ - - def mkSplit1Impl[L[_], FO[_[_]], FI[_[_]]] - (implicit lTag: WeakTypeTag[L[_]], foTag: WeakTypeTag[FO[Any]], fiTag: WeakTypeTag[FI[Any]]): Tree = { - val lTpe = lTag.tpe - - val (foTpe, fiTpe) = c.openImplicits.headOption match { - case Some(ImplicitCandidate(_, _, TypeRef(_, _, List(_, fo, fi)), _)) => (fo, fi) - case _ => (foTag.tpe.typeConstructor, fiTag.tpe.typeConstructor) - } - - if (isReprType1(lTpe)) - abort("No Split1 instance available for HList or Coproduct") - - val lParam = lTpe.typeParams.head - val lParamTpe = lParam.asType.toType - val lDealiasedTpe = appliedType(lTpe, lParamTpe).dealias - - def balanced(args: List[Type]): Boolean = - args.find(_.contains(lParam)).exists { pivot => - !(pivot =:= lParamTpe) && args.forall { arg => - arg =:= pivot || !arg.contains(lParam) - } - } - - val name = TypeName(c.freshName()) - val (oTpt, iTpt) = lDealiasedTpe match { - case tpe @ TypeRef(_, _, args) if balanced(args) => - val pivot = args.find(_.contains(lParam)).get - val oPoly = polyType(List(lParam), appliedType(tpe.typeConstructor, args.map(arg => if (arg =:= pivot) lParamTpe else arg))) - val oTpt = appliedTypTree1(oPoly, lParamTpe, name) - val iPoly = polyType(List(lParam), pivot) - val iTpt = appliedTypTree1(iPoly, lParamTpe, name) - (oTpt, iTpt) - case other => - c.abort(c.enclosingPosition, s"Can't split $other into a non-trivial outer and inner type constructor") - } - - val oName = TypeName(c.freshName("O")) - val iName = TypeName(c.freshName("I")) - val split1 = objectRef[Split1.type] - - q""" - type $oName[$name] = $oTpt - type $iName[$name] = $iTpt - $split1.instance[$foTpe, $fiTpe, $oName, $iName] - """ - } -} +trait Split10 extends Split10ScalaCompat diff --git a/core/src/main/scala/shapeless/hlists.scala b/core/src/main/scala/shapeless/hlists.scala index af2546659..d223f5dc4 100644 --- a/core/src/main/scala/shapeless/hlists.scala +++ b/core/src/main/scala/shapeless/hlists.scala @@ -17,10 +17,8 @@ package shapeless import scala.language.dynamics -import scala.language.experimental.macros import scala.annotation.tailrec -import scala.reflect.macros.whitebox /** * `HList` ADT base trait. @@ -58,7 +56,7 @@ sealed trait HNil extends HList { */ case object HNil extends HNil -object HList extends Dynamic { +object HList extends Dynamic with HListScalaCompat { import ops.hlist._ import syntax.HListOps @@ -99,22 +97,6 @@ object HList extends Dynamic { val #: = shapeless.:: } - /** - * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = HList.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = HList.`'a, 'b, 'c`.T - * type TwoTrueStr = HList.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistType - @tailrec def unsafeGet(l: HList, i: Int): Any = (l: @unchecked) match { @@ -202,9 +184,7 @@ object HList extends Dynamic { * @author Andreas Koestler */ -trait NatProductArgs extends Dynamic { - def applyDynamic(method: String)(args: Int*): Any = macro ProductMacros.forwardNatImpl -} +trait NatProductArgs extends Dynamic with NatProductArgsScalaCompat /** * Trait supporting mapping dynamic argument lists to HList arguments. * @@ -225,9 +205,7 @@ trait NatProductArgs extends Dynamic { * "Product" suffix) which accepts a single HList argument. * */ -trait ProductArgs extends Dynamic { - def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardImpl -} +trait ProductArgs extends Dynamic with ProductArgsScalaCompat /** * Trait supporting mapping HList arguments to argument lists, inverse of ProductArgs. @@ -249,10 +227,7 @@ trait ProductArgs extends Dynamic { * is rewritten to an application of the target method * */ -trait FromProductArgs extends Dynamic { - def applyDynamic(method: String)(hlist: HList): Any = - macro ProductMacros.forwardFromProductImpl -} +trait FromProductArgs extends Dynamic with FromProductArgsScalaCompat /** * Trait supporting mapping dynamic argument lists to singleton-typed HList arguments. @@ -273,112 +248,4 @@ trait FromProductArgs extends Dynamic { * application is rewritten to an application of an implementing method (identified by the * "Product" suffix) which accepts a single HList argument. */ -trait SingletonProductArgs extends Dynamic { - def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardSingletonImpl -} - -class ProductMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { - import c.universe._ - - def forwardImpl(method: Tree)(args: Tree*): Tree = forward(method, args, false) - - def forwardNatImpl(method: Tree)(args: Tree*): Tree = forwardNat(method, args) - - def forwardSingletonImpl(method: Tree)(args: Tree*): Tree = forward(method, args, true) - - def forwardNat(method: Tree, args: Seq[Tree]): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString+"NatProduct") - - if(lhsTpe.member(methodName) == NoSymbol) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val meth = lhsTpe.member(methodName).asMethod - - if (!meth.paramLists.isEmpty && (meth.paramLists(0) forall (_.isImplicit))) { - val typeParamsTree = mkProductNatTypeParamsImpl(args) - q""" $lhs.$methodName[${typeParamsTree}] """ - } else { - val argsTree = mkProductNatImpl(args) - q""" $lhs.$methodName($argsTree) """ - } - } - - def forward(method: Tree, args: Seq[Tree], narrow: Boolean): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString+"Product") - - if(lhsTpe.member(methodName) == NoSymbol) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val argsTree = mkProductImpl(args, narrow) - - q""" $lhs.$methodName($argsTree) """ - } - - def forwardFromProductImpl(method: Tree)(hlist: Tree): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - - if (!methodString.matches(".*Product$")) - c.abort(c.enclosingPosition, s"missing method '$methodString'") - - val methodName = TermName(methodString.replaceAll("Product$", "")) - - if(!lhsTpe.member(methodName).isMethod) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val methodSym = lhsTpe.member(methodName).asMethod - val paramss = methodSym.paramLists.filterNot(_.forall(_.isImplicit)) - val argss = paramss.map(_.map(_ => TermName(c.freshName("pat")))) - val names = argss.flatten - - val pattern = - names.foldRight(q"_root_.shapeless.HNil": Tree) { - case (nme, acc) => pq"_root_.shapeless.::($nme, $acc)" - } - - q""" - $hlist match { - case $pattern => $lhs.$methodName(...$argss) - } - """ - } - - def mkProductImpl(args: Seq[Tree], narrow: Boolean): Tree = { - args.foldRight((hnilTpe, q"_root_.shapeless.HNil: $hnilTpe": Tree)) { - case(elem, (accTpe, accTree)) => - val (neTpe, neTree) = if(narrow) narrowValue(elem) else (elem.tpe, elem) - (appliedType(hconsTpe, List(neTpe, accTpe)), q"""_root_.shapeless.::[$neTpe, $accTpe]($neTree, $accTree)""") - }._2 - } - - def mkProductNatImpl(args: Seq[Tree]): Tree = { - args.foldRight((tq"_root_.shapeless.HNil", q"_root_.shapeless.HNil: $hnilTpe"): (Tree, Tree)) { - case(NatLiteral(n), (accTpt, accTree)) => - val neTpt = mkNatTpt(n) - val neTree = mkNatValue(n) - (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", q"""_root_.shapeless.::[$neTpt, $accTpt]($neTree, $accTree)""") - case (elem, _) => - c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") - }._2 - } - - def mkProductNatTypeParamsImpl(args: Seq[Tree]): Tree = { - args.foldRight((tq"_root_.shapeless.HNil", tq"_root_.shapeless.HNil"): (Tree, Tree)) { - case (NatLiteral(n), (accTpt, _)) => - val neTpt = mkNatTpt(n) - (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", tq"""_root_.shapeless.::[$neTpt, $accTpt]""") - case (elem, _) => - c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") - }._2 - } -} +trait SingletonProductArgs extends Dynamic with SingletonProductArgsScalaCompat diff --git a/core/src/main/scala/shapeless/hmap.scala b/core/src/main/scala/shapeless/hmap.scala index cdba5c2b3..1379a2907 100644 --- a/core/src/main/scala/shapeless/hmap.scala +++ b/core/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[HMap.this.type, K, V] = Case1[this.type, K, V](get(_).get) } object HMap { diff --git a/core/src/main/scala/shapeless/labelled.scala b/core/src/main/scala/shapeless/labelled.scala index 9e568d10f..3b84a967a 100644 --- a/core/src/main/scala/shapeless/labelled.scala +++ b/core/src/main/scala/shapeless/labelled.scala @@ -16,9 +16,6 @@ package shapeless -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - object labelled { /** The type of fields with keys of singleton type `K` and value type `V`. */ @@ -34,13 +31,10 @@ object labelled { trait Labelling[T] extends DepFn0 with Serializable { type Out <: HList } -object Labelling { +object Labelling extends LabellingScalaCompat { type Aux[T, Out0] = Labelling[T] { type Out = Out0 } def apply[T](implicit lab: Labelling[T]): Aux[T, lab.Out] = lab - implicit def mkLabelling[T]: Labelling[T] = - macro LabelledMacros.mkLabelling[T] - def instance[T, L <: HList](labels: L): Aux[T, L] = new Labelling[T] { type Out = L def apply(): L = labels @@ -83,98 +77,3 @@ trait FieldOf[V] { type F = FieldType[this.type, V] def ->>(v: V): FieldType[this.type, V] = field[this.type](v) } - -class LabelledMacros(override val c: whitebox.Context) extends GenericMacros(c) with SingletonTypeUtils { - import c.universe._ - import internal.constantType - - private def commaSeparated(str: String): List[String] = { - val builder = List.newBuilder[String] - var i, j, k = 0 - while (j < str.length) { - str.charAt(j) match { - case ',' if k == 0 => - builder += str.substring(i, j).trim - i = j + 1 - case '(' | '[' => - k += 1 - case ')' | ']' => - k = k - 1 max 0 - case _ => - } - - j += 1 - } - - val last = str.substring(i, j).trim - if (last.nonEmpty) builder += last - builder.result() - } - - private def parseTypeOrFail(tpe: String): Type = - parseType(tpe).getOrElse(abort(s"Malformed literal or standard type $tpe")) - - private def parseLiteralTypeOrFail(tpe: String): Type = - parseLiteralType(tpe).getOrElse(abort(s"Malformed literal type $tpe")) - - private def labelsOf(tpe: Type): List[Constant] = - if (isProduct(tpe)) fieldsOf(tpe).map { case (f, _) => nameAsValue(f) } - else if (isCoproduct(tpe)) ctorsOf(tpe).map(c => nameAsValue(nameOf(c))) - else abort(s"$tpe is not case class like or the root of a sealed family of types") - - def mkLabelledGeneric[T: WeakTypeTag, R]: Tree = { - val tpe = weakTypeOf[T] - val keys = labelsOf(tpe).map(constantType) - val generic @ q"$_.instance[$_, ${repr: Tree}]($_, $_)" = (mkGeneric[T]: @unchecked) - val isProduct = repr.tpe <:< hlistTpe - val values = if (isProduct) unpackHList(repr.tpe) else unpackCoproduct(repr.tpe) - val items = keys.zip(values).map((FieldType.apply _).tupled) - val labelled = if (isProduct) mkHListTpe(items) else mkCoproductTpe(items) - q"${reify(LabelledGeneric)}.unsafeInstance[$tpe, $labelled]($generic)" - } - - def mkLabelling[T: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T] - val labels = labelsOf(tpe) - val labelsType = mkHListTpe(labels.map(constantType)) - val labelsValue = mkHListValue(labels.map(Literal.apply)) - q"${reify(Labelling)}.instance[$tpe, $labelsType]($labelsValue.asInstanceOf[$labelsType])" - } - - def recordType(tpeSelector: Tree): Tree = - labelledType(tpeSelector, "record", hnilTpe, hconsTpe) - - def unionType(tpeSelector: Tree): Tree = - labelledType(tpeSelector, "union", cnilTpe, cconsTpe) - - def labelledType(tpeSelector: Tree, variety: String, nil: Type, cons: Type): Tree = { - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val labelledTpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => - element.split("->") match { - case Array(keyString, valueString) => - val key = parseLiteralTypeOrFail(keyString.trim) - val value = parseTypeOrFail(valueString.trim) - appliedType(cons, FieldType(key, value), acc) - case _ => - abort(s"Malformed $variety type $tpeString") - } - } - - typeCarrier(labelledTpe) - } - - def hlistType(tpeSelector: Tree): Tree = - nonLabelledType(tpeSelector, hnilTpe, hconsTpe) - - def coproductType(tpeSelector: Tree): Tree = - nonLabelledType(tpeSelector, cnilTpe, cconsTpe) - - def nonLabelledType(tpeSelector: Tree, nil: Type, cons: Type): Tree = { - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val tpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => - appliedType(cons, parseTypeOrFail(element), acc) - } - - typeCarrier(tpe) - } -} diff --git a/core/src/main/scala/shapeless/lazy.scala b/core/src/main/scala/shapeless/lazy.scala index 99ab36aee..234f8d468 100644 --- a/core/src/main/scala/shapeless/lazy.scala +++ b/core/src/main/scala/shapeless/lazy.scala @@ -106,9 +106,7 @@ import scala.annotation.implicitNotFound * */ @implicitNotFound("could not find Lazy implicit value of type ${T}") -trait Lazy[+T] extends Serializable { - val value: T - +trait Lazy[+T] extends Serializable with LazyScalaCompat[T] { def map[U](f: T => U): Lazy[U] = Lazy { f(value) } def flatMap[U](f: T => Lazy[U]): Lazy[U] = Lazy { f(value).value } } diff --git a/core/src/main/scala/shapeless/lenses.scala b/core/src/main/scala/shapeless/lenses.scala index 4427de7b2..d7913d66a 100644 --- a/core/src/main/scala/shapeless/lenses.scala +++ b/core/src/main/scala/shapeless/lenses.scala @@ -17,11 +17,10 @@ package shapeless import scala.language.dynamics - -import labelled.{ FieldType, field } -import ops.coproduct.{ Inject, Selector => CSelector } -import ops.hlist.{ At, Init, Last, Prepend, Selector, ReplaceAt, Replacer, Tupler } -import ops.record.{ Selector => RSelector, Updater } +import labelled.{FieldType, field} +import ops.coproduct.{Inject, Selector => CSelector} +import ops.hlist.{At, Init, Last, Prepend, ReplaceAt, Replacer, Selector, Tupler} +import ops.record.{Updater, Selector => RSelector} trait Lens[S, A] extends LPLens[S, A] { outer => def get(s: S): A @@ -162,7 +161,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] { diff --git a/core/src/main/scala/shapeless/nat.scala b/core/src/main/scala/shapeless/nat.scala index 2f4cebeea..1ec83923a 100644 --- a/core/src/main/scala/shapeless/nat.scala +++ b/core/src/main/scala/shapeless/nat.scala @@ -16,11 +16,6 @@ package shapeless -import scala.language.experimental.macros - -import scala.annotation.tailrec -import scala.reflect.macros.whitebox - /** * Base trait for type level natural numbers. * @@ -53,12 +48,10 @@ class _0 extends Nat with Serializable { * * @author Miles Sabin */ -object Nat extends Nats { +object Nat extends Nats with NatScalaCompat { import ops.nat._ import syntax.NatOps - implicit def apply(i: Int): Nat = macro NatMacros.materializeWidened - /** The natural number 0 */ type _0 = shapeless._0 val _0: _0 = new _0 @@ -69,56 +62,3 @@ object Nat extends Nats { implicit def natOps[N <: Nat](n : N) : NatOps[N] = new NatOps(n) } - -class NatMacros(val c: whitebox.Context) extends NatMacroDefns { - import c.universe._ - - def materializeWidened(i: Tree): Tree = - i match { - case NatLiteral(n) => mkNatValue(n) - case _ => - c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") - } -} - -trait NatMacroDefns { - val c: whitebox.Context - import c.universe._ - - object NatLiteral { - def unapply(i: Tree): Option[Int] = - i match { - case Literal(Constant(n: Int)) if n >= 0 => Some(n) - case _ => None - } - } - - def mkNatTpt(i: Int): Tree = { - val succSym = typeOf[Succ[_]].typeConstructor.typeSymbol - val _0Sym = typeOf[_0].typeSymbol - - @tailrec - def loop(i: Int, acc: Tree): Tree = { - if(i == 0) acc - else loop(i-1, AppliedTypeTree(Ident(succSym), List(acc))) - } - - loop(i, Ident(_0Sym)) - } - - def mkNatTpe(i: Int): Type = { - val succTpe = typeOf[Succ[_]].typeConstructor - val _0Tpe = typeOf[_0] - - @tailrec - def loop(i: Int, acc: Type): Type = { - if(i == 0) acc - else loop(i-1, appliedType(succTpe, acc)) - } - - loop(i, _0Tpe) - } - - def mkNatValue(i: Int): Tree = - q""" new ${mkNatTpt(i)} """ -} diff --git a/core/src/main/scala/shapeless/ops/hlists.scala b/core/src/main/scala/shapeless/ops/hlists.scala index 623f8c47b..31d68282c 100644 --- a/core/src/main/scala/shapeless/ops/hlists.scala +++ b/core/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: HKernelAux.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]): HKernelAux.Aux[H :: T, HConsHKernel[H, CtOut]] = new HKernelAux[H :: T] { type Out = HConsHKernel[H, CtOut] def apply() = HConsHKernel[H, CtOut](ct()) } @@ -1061,7 +1061,7 @@ object hlist { * * @author Andreas Koestler */ - trait Grouper[L <: HList, N <: Nat, Step <: Nat] extends DepFn1[L] with Serializable { + trait Grouper[L <: HList, N <: Nat, Step <: Nat] extends DepFn1[L] with Serializable { type Out <: HList } @@ -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 @@ -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 @@ -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 diff --git a/core/src/main/scala/shapeless/ops/nat.scala b/core/src/main/scala/shapeless/ops/nat.scala index 8b624fd8c..cf1d82b8b 100644 --- a/core/src/main/scala/shapeless/ops/nat.scala +++ b/core/src/main/scala/shapeless/ops/nat.scala @@ -17,10 +17,6 @@ package shapeless package ops -import scala.annotation.tailrec -import scala.reflect.macros.whitebox -import scala.language.experimental.macros - object nat { /** @@ -140,14 +136,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 +156,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]] {} } /** @@ -595,7 +591,7 @@ object nat { def apply(): Int } - object ToInt { + object ToInt extends ToIntScalaCompat { def apply[N <: Nat](implicit toInt: ToInt[N]): ToInt[N] = toInt final class Inst[N <: Nat](i: Int) extends ToInt[N] { @@ -603,35 +599,5 @@ object nat { } implicit val toInt0: ToInt[_0] = new Inst[_0](0) - implicit def toIntSuccM[N <: Nat]: ToInt[N] = macro ToIntMacros.applyImpl[N] - } - - class ToIntMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - val _0Tpe = typeOf[_0] - val succTpe = typeOf[Succ[_]].typeConstructor - val succSym = succTpe.typeSymbol - val succPre = prefix(succTpe) - - - def applyImpl[N <: Nat](implicit nTag: WeakTypeTag[N]): Tree = { - val tpe = nTag.tpe.dealias - - @tailrec - def count(u: Type, acc: Int): Int = { - if(u <:< _0Tpe) acc - else (u baseType succSym) match { - case TypeRef(pre, _, List(n)) if pre =:= succPre => count(n, acc + 1) - case _ => abort(s"$tpe is not a Nat type") - } - } - - q""" - new _root_.shapeless.ops.nat.ToInt.Inst(${count(tpe, 0)}). - asInstanceOf[ _root_.shapeless.ops.nat.ToInt[$tpe]] - """ - } } - } diff --git a/core/src/main/scala/shapeless/ops/records.scala b/core/src/main/scala/shapeless/ops/records.scala index 84475ebaf..fab7345c6 100644 --- a/core/src/main/scala/shapeless/ops/records.scala +++ b/core/src/main/scala/shapeless/ops/records.scala @@ -17,9 +17,6 @@ package shapeless package ops -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - import poly._ //object record { @@ -37,12 +34,9 @@ package record { @annotation.implicitNotFound(msg = "No field ${K} in record ${R}") sealed abstract class Selector[R <: HList, K] extends DepFn1[R] with Serializable - object Selector { + object Selector extends SelectorScalaCompat { type Aux[R <: HList, K, O] = Selector[R, K] { type Out = O } def apply[R <: HList, K](implicit selector: Selector[R, K]): Aux[R, K, selector.Out] = selector - - implicit def materialize[R <: HList, K, O]: Aux[R, K, O] = - macro SelectorMacros.materialize[R, K] } final class UnsafeSelector(i: Int) extends Selector[HList, Any] { @@ -50,24 +44,6 @@ package record { def apply(record: HList): Any = HList.unsafeGet(record, i) } - class SelectorMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { - val record = weakTypeOf[R].dealias - val key = weakTypeOf[K].dealias - if (!(record <:< hlistTpe)) - abort(s"$record is not a record type") - - findField(record, key) match { - case Some((k, v, i)) => - q"new ${typeOf[UnsafeSelector]}($i).asInstanceOf[${reify(Selector)}.Aux[$record, $k, $v]]" - case _ => - abort(s"No field $key in record type $record") - } - } - } - /** * Type class supporting multiple record field selection. * @@ -108,12 +84,9 @@ package record { type Out <: HList } - object Updater { + object Updater extends UpdaterScalaCompat { type Aux[L <: HList, E, O <: HList] = Updater[L, E] { type Out = O } def apply[L <: HList, E](implicit updater: Updater[L, E]): Aux[L, E, updater.Out] = updater - - implicit def meterialize[L <: HList, F, O]: Aux[L, F, O] = - macro UpdaterMacros.materialize[L, F] } final class UnsafeUpdater(i: Int) extends Updater[HList, Any] { @@ -121,26 +94,6 @@ package record { def apply(l: HList, e: Any): HList = HList.unsafeUpdateAppend(l, i, e) } - class UpdaterMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def materialize[L <: HList: WeakTypeTag, E: WeakTypeTag]: Tree = { - val list = weakTypeOf[L].dealias - val element = weakTypeOf[E].dealias - if (!(list <:< hlistTpe)) - abort(s"$list is not a record type") - - val (updated, i) = { - val elements = unpackHList(list) - val i = elements.indexWhere(_ =:= element) - if (i < 0) (elements :+ element, elements.length) - else (elements.updated(i, element), i) - } - - q"new ${typeOf[UnsafeUpdater]}($i).asInstanceOf[${reify(Updater)}.Aux[$list, $element, ${mkHListTpe(updated)}]]" - } - } - /** * Type class support record merging. * @@ -351,12 +304,9 @@ package record { type Out <: HList } - object Modifier { + object Modifier extends ModifierScalaCompat { type Aux[R <: HList, K, A, B, O <: HList] = Modifier[R, K, A, B] { type Out = O } def apply[R <: HList, K, A, B](implicit modifier: Modifier[R, K, A, B]): Aux[R, K, A, B, modifier.Out] = modifier - - implicit def materialize[R <: HList, K, A, B, O <: HList]: Aux[R, K, A, B, O] = - macro ModifierMacros.materialize[R, K, A, B] } final class UnsafeModifier(i: Int) extends Modifier[HList, Any, Any, Any] { @@ -364,28 +314,6 @@ package record { def apply(record: HList, f: Any => Any): HList = HList.unsafeUpdateWith(record, i, f) } - class ModifierMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag, A: WeakTypeTag, B: WeakTypeTag]: Tree = { - val record = weakTypeOf[R].dealias - val key = weakTypeOf[K].dealias - if (!(record <:< hlistTpe)) - abort(s"$record is not a record type") - - val a = weakTypeOf[A] - val b = weakTypeOf[B] - val fields = unpackHList(record) - findField(fields, key) match { - case Some((k, v, i)) if v <:< a => - val out = mkHListTpe(fields.updated(i, FieldType(k, b))) - q"new ${typeOf[UnsafeModifier]}($i).asInstanceOf[${reify(Modifier)}.Aux[$record, $k, $a, $b, $out]]" - case _ => - abort(s"No field $key in record type $record") - } - } - } - /** * Type class supporting record field removal. * @@ -396,12 +324,9 @@ package record { type Out <: (Any, HList) } - object Remover { + object Remover extends RemoverScalaCompat { type Aux[R <: HList, K, O] = Remover[R, K] { type Out = O } def apply[R <: HList, K](implicit remover: Remover[R, K]): Aux[R, K, remover.Out] = remover - - implicit def materialize[R <: HList, K, V, O <: HList]: Aux[R, K, (V, O)] = - macro RemoverMacros.materialize[R, K] } final class UnsafeRemover(i: Int) extends Remover[HList, Any] { @@ -409,27 +334,6 @@ package record { def apply(record: HList): (Any, HList) = HList.unsafeRemove(record, i) } - class RemoverMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { - val record = weakTypeOf[R].dealias - val key = weakTypeOf[K].dealias - if (!(record <:< hlistTpe)) - abort(s"$record is not a record type") - - val fields = unpackHList(record) - findField(fields, key) match { - case Some((k, v, i)) => - val (prefix, suffix) = fields.splitAt(i) - val out = mkHListTpe(prefix ++ suffix.tail) - q"new ${typeOf[UnsafeRemover]}($i).asInstanceOf[${reify(Remover)}.Aux[$record, $k, ($v, $out)]]" - case _ => - abort(s"No field $key in record type $record") - } - } - } - /** * Type class supporting removal and re-insertion of an element (possibly unlabelled). * @@ -547,27 +451,8 @@ package record { @annotation.implicitNotFound(msg = "Record ${R} contains field ${K}") final class LacksKey[R <: HList, K] - object LacksKey { + object LacksKey extends LacksKeyScalaCompat { def apply[R <: HList, K](implicit ev: LacksKey[R, K]): LacksKey[R, K] = ev - - implicit def materialize[R <: HList, K]: LacksKey[R, K] = - macro LacksKeyMacros.materialize[R, K] - } - - class LacksKeyMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - - def materialize[R <: HList: WeakTypeTag, K: WeakTypeTag]: Tree = { - val record = weakTypeOf[R].dealias - val key = weakTypeOf[K].dealias - if (!(record <:< hlistTpe)) - abort(s"$record is not a record type") - - findField(record, key) match { - case None => q"new ${weakTypeOf[LacksKey[R, K]]}" - case _ => abort(s"Record type $record contains field $key") - } - } } /** diff --git a/core/src/main/scala/shapeless/ops/traversables.scala b/core/src/main/scala/shapeless/ops/traversables.scala index 45babd7c0..e42e88f97 100644 --- a/core/src/main/scala/shapeless/ops/traversables.scala +++ b/core/src/main/scala/shapeless/ops/traversables.scala @@ -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 diff --git a/core/src/main/scala/shapeless/ops/tuples.scala b/core/src/main/scala/shapeless/ops/tuples.scala index b0713f5ee..e8ec9af30 100644 --- a/core/src/main/scala/shapeless/ops/tuples.scala +++ b/core/src/main/scala/shapeless/ops/tuples.scala @@ -1243,7 +1243,9 @@ 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/src/main/scala/shapeless/ops/zipper.scala b/core/src/main/scala/shapeless/ops/zipper.scala index 4e8c709b8..714c37d2a 100644 --- a/core/src/main/scala/shapeless/ops/zipper.scala +++ b/core/src/main/scala/shapeless/ops/zipper.scala @@ -200,7 +200,7 @@ object zipper { trait Root[Z] extends DepFn1[Z] with Serializable - object Root extends { + object Root { def apply[Z](implicit root: Root[Z]): Aux[Z, root.Out] = root type Aux[Z, Out0] = Root[Z] { type Out = Out0 } diff --git a/core/src/main/scala/shapeless/package.scala b/core/src/main/scala/shapeless/package.scala index 6ef12290b..b72f23e7f 100644 --- a/core/src/main/scala/shapeless/package.scala +++ b/core/src/main/scala/shapeless/package.scala @@ -14,10 +14,6 @@ * limitations under the License. */ -import scala.language.experimental.macros - -import scala.reflect.macros.whitebox - package object shapeless extends ScalaVersionSpecifics { def unexpected : Nothing = sys.error("Unexpected invocation") @@ -57,8 +53,8 @@ package object shapeless extends ScalaVersionSpecifics { } // Quantifiers - type ∃[P[_]] = P[T] forSome { type T } - type ∀[P[_]] = ¬[∃[({ type λ[X] = ¬[P[X]]})#λ]] + // TODO type ∃[P[_]] = P[_] + // TODO type ∀[P[_]] = ¬[∃[({ type λ[X] = ¬[P[X]]})#λ]] /** `Optic` definitions */ val optic = OpticDefns @@ -107,63 +103,4 @@ package object shapeless extends ScalaVersionSpecifics { def everywhere[T, R](f: Poly)(t: T)( implicit cse: => Case1.Aux[EverywhereAux[f.type], T, R] ): R = cse(t) - - def cachedImplicit[T]: T = macro CachedImplicitMacros.cachedImplicitImpl[T] -} - -package shapeless { - class CachedImplicitMacros(val c: whitebox.Context) { - import c.universe._ - - def cachedImplicitImpl[T](implicit tTag: WeakTypeTag[T]): Tree = { - val casted = c.asInstanceOf[reflect.macros.runtime.Context] - val typer = casted.callsiteTyper - val global: casted.universe.type = casted.universe - val analyzer: global.analyzer.type = global.analyzer - val tCtx = typer.context - val owner = tCtx.owner - if(!owner.isVal && !owner.isLazy) - c.abort(c.enclosingPosition, "cachedImplicit should only be used to initialize vals and lazy vals") - val tTpe = weakTypeOf[T] - val application = casted.macroApplication - val tpe = { - val tpe0 = - if (tTpe.typeSymbol.isParameter) owner.tpe.asInstanceOf[Type] - else tTpe - tpe0.finalResultType - } - val gTpe = tpe.asInstanceOf[global.Type] - - // Run our own custom implicit search that isn't allowed to find - // the thing we are enclosed in - val sCtx = tCtx.makeImplicit(false) - val is = new analyzer.ImplicitSearch( - tree = application, - pt = gTpe, - isView = false, - context0 = sCtx, - pos0 = c.enclosingPosition.asInstanceOf[global.Position] - ) { - override def searchImplicit( - implicitInfoss: List[List[analyzer.ImplicitInfo]], - isLocalToCallsite: Boolean - ): analyzer.SearchResult = { - val filteredInput = implicitInfoss.map { infos => - infos.filter { info => - val sym = if(info.sym.isLazy) info.sym else info.sym.accessedOrSelf - sym.owner != owner.owner || (!sym.isVal && !sym.isLazy) - } - } - super.searchImplicit(filteredInput, isLocalToCallsite) - } - } - val best = is.bestImplicit - if (best.isFailure) { - val errorMsg = implicitNotFoundMessage(c)(tpe) - c.abort(c.enclosingPosition, errorMsg) - } else { - best.tree.asInstanceOf[Tree] - } - } - } } diff --git a/core/src/main/scala/shapeless/poly.scala b/core/src/main/scala/shapeless/poly.scala index 5ece0159d..54c593adc 100644 --- a/core/src/main/scala/shapeless/poly.scala +++ b/core/src/main/scala/shapeless/poly.scala @@ -16,10 +16,6 @@ package shapeless -import language.experimental.macros - -import reflect.macros.whitebox - // Typically the contents of this object will be imported via val alias `poly` in the shapeless package object. object PolyDefns extends Cases { import shapeless.ops.{ hlist => hl } @@ -39,7 +35,7 @@ object PolyDefns extends Cases { def apply[T, U](t: T, u: U)(implicit ev: (T :: U :: HNil) =:= L) = value(t :: u :: HNil) } - object Case extends CaseInst { + object Case extends CaseInst with CaseScalaCompat { type Aux[P, L <: HList, Result0] = Case[P, L] { type Result = Result0 } type Hom[P, T] = Aux[P, T :: HNil, T] @@ -47,12 +43,6 @@ object PolyDefns extends Cases { type Result = R val value = v } - - implicit def materializeFromValue1[P, F[_], T]: Case[P, F[T] :: HNil] = - macro PolyMacros.materializeFromValueImpl[P, F[T], T] - - implicit def materializeFromValue2[P, T]: Case[P, T :: HNil] = - macro PolyMacros.materializeFromValueImpl[P, T, T] } type Case0[P] = Case[P, HNil] @@ -73,10 +63,11 @@ 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] { - type Result = V - val value = (t : T :: HNil) => cF(cG.value(t)) - } + (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)) + } } /** @@ -123,7 +114,7 @@ object PolyDefns extends Cases { finalCall: Case.Aux[F, Head :: Tail, Result0] ): Case.Aux[BF, Tail, Result0] = new Case[BF, Tail] { type Result = Result0 - val value: Tail => Result = { tail: Tail => + val value: Tail => Result = { (tail: Tail) => finalCall.value(witnessBF.value.head :: tail) } } @@ -148,7 +139,7 @@ object PolyDefns extends Cases { reverseSplit: ops.hlist.ReverseSplit.Aux[AllParameters, CurrentLength, CurrentParameter :: ParameterAccumulator, RestParameters], hasRestParameters: RestParameters <:< (_ :: _) ): Case1.Aux[Self, CurrentParameter, Curried[F, CurrentParameter :: ParameterAccumulator]] = Case1 { - nextParameter: CurrentParameter => + (nextParameter: CurrentParameter) => Curried[F, CurrentParameter :: ParameterAccumulator](nextParameter :: witnessSelf.value.parameters) } } @@ -161,7 +152,7 @@ object PolyDefns extends Cases { reverse: ops.hlist.Reverse.Aux[LastParameter :: ParameterAccumulator, AllParameters], finalCall: Case.Aux[F, AllParameters, Result0] ): Case1.Aux[Self, LastParameter, Result0] = Case1 { - lastParameter: LastParameter => + (lastParameter: LastParameter) => finalCall(reverse(lastParameter :: witnessSelf.value.parameters)) } } @@ -170,11 +161,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]: this.Case.Aux[U, R] = at[U](f) } trait LowPriorityLiftFunction1 extends Poly1 { - implicit def default[T] = at[T](_ => HNil : HNil) + implicit def default[T]: this.Case.Aux[T, HNil] = at[T](_ => HNil : HNil) } /** @@ -182,11 +173,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]: this.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]: Case.Aux[LowPriorityLiftU.this.type, L, HNil] = new ProductCase[L] { type Result = HNil val value = (l : L) => HNil } @@ -197,7 +188,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]): Case.Aux[LiftU.this.type, L, caseT.Result :: HNil] = new ProductCase[L] { type Result = caseT.Result :: HNil val value = (l : L) => caseT(l) :: HNil } @@ -210,7 +201,7 @@ object PolyDefns extends Cases { */ trait ~>[F[_], G[_]] extends Poly1 { def apply[T](f : F[T]) : G[T] - implicit def caseUniv[T]: Case.Aux[F[T], G[T]] = at[F[T]](apply(_)) + implicit def caseUniv[T]: this.Case.Aux[F[T], G[T]] = at[F[T]](apply(_)) } object ~> { @@ -316,26 +307,3 @@ trait Poly0 extends Poly { val value = (l : HNil) => t } } - -class PolyMacros(val c: whitebox.Context) { - import c.universe._ - - import PolyDefns.Case - - def materializeFromValueImpl[P: WeakTypeTag, FT: WeakTypeTag, T: WeakTypeTag]: Tree = { - val pTpe = weakTypeOf[P] - val ftTpe = weakTypeOf[FT] - val tTpe = weakTypeOf[T] - - val recTpe = weakTypeOf[Case[P, FT :: HNil]] - if(c.openImplicits.tail.exists(_.pt =:= recTpe)) - c.abort(c.enclosingPosition, s"Diverging implicit expansion for Case.Aux[$pTpe, $ftTpe :: HNil]") - - val value = pTpe match { - case SingleType(_, f) => f - case other => c.abort(c.enclosingPosition, "Can only materialize cases from singleton values") - } - - q""" $value.caseUniv[$tTpe] """ - } -} diff --git a/core/src/main/scala/shapeless/records.scala b/core/src/main/scala/shapeless/records.scala index 0ad549117..f696e436a 100644 --- a/core/src/main/scala/shapeless/records.scala +++ b/core/src/main/scala/shapeless/records.scala @@ -17,9 +17,6 @@ package shapeless import scala.language.dynamics -import scala.language.experimental.macros - -import scala.reflect.macros.whitebox /** * Record operations on `HList`'s with field-like elements. @@ -55,11 +52,7 @@ object record { * xyz("y") // == "foo" * }}} */ - object Record extends Dynamic { - def applyDynamic(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordEmptyImpl - def applyDynamicNamed(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordNamedImpl - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.recordType - } + object Record extends Dynamic with RecordScalaCompat } /** @@ -82,10 +75,7 @@ object record { * application of an implementing method (identified by the "Record" suffix) which * accepts a single record argument. */ -trait RecordArgs extends Dynamic { - def applyDynamic(method: String)(): Any = macro RecordMacros.forwardImpl - def applyDynamicNamed(method: String)(rec: Any*): Any = macro RecordMacros.forwardNamedImpl -} +trait RecordArgs extends Dynamic with RecordArgsScalaCompat /** * Trait supporting mapping record arguments to named argument lists, inverse of RecordArgs. @@ -106,79 +96,4 @@ trait RecordArgs extends Dynamic { * (the called method named minus the "Record" suffix) by name and type and the application * is rewritten to an application of the target method */ -trait FromRecordArgs extends Dynamic { - def applyDynamic[L <: HList](method: String)(rec: L): Any = macro RecordMacros.forwardFromRecordImpl[L] -} - -class RecordMacros(val c: whitebox.Context) extends CaseClassMacros { - import c.universe._ - import internal.constantType - - val hconsValueTree: Tree = reify(::).tree - val hnilValueTree: Tree = reify(HNil: HNil).tree - - def mkRecordEmptyImpl(method: Tree)(rec: Tree*): Tree = { - if (rec.nonEmpty) abort("this method must be called with named arguments") - hnilValueTree - } - - def mkRecordNamedImpl(method: Tree)(rec: Tree*): Tree = { - val q"${methodString: String}" = (method: @unchecked) - if (methodString != "apply") abort(s"this method must be called as 'apply' not '$methodString'") - mkRecordImpl(rec: _*) - } - - def forwardImpl(method: Tree)(): Tree = - forwardNamedImpl(method)() - - def forwardNamedImpl(method: Tree)(rec: Tree*): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString + "Record") - if (lhsTpe.member(methodName) == NoSymbol) - abort(s"missing method '$methodName'") - - val recTree = mkRecordImpl(rec: _*) - q"$lhs.$methodName($recTree)" - } - - def forwardFromRecordImpl[L <: HList](method: Tree)(rec: Expr[L]): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - val q"${methodString: String}" = (method: @unchecked) - if (!methodString.matches(".*Record$")) - abort(s"missing method '$methodString'") - - val methodName = TermName(methodString.replaceAll("Record$", "")) - if (!lhsTpe.member(methodName).isMethod) - abort(s"missing method '$methodName'") - - val params = mkParamsImpl(lhsTpe.member(methodName).asMethod, rec) - q"$lhs.$methodName(...$params)" - } - - def mkRecordImpl(rec: Tree*): Tree = { - def mkElem(key: Type, value: Tree): Tree = - q"$value.asInstanceOf[${FieldType(key, value.tpe.widen)}]" - - def promoteElem(elem: Tree): Tree = elem match { - case q"$_(${Literal(k)}, $v)" => mkElem(constantType(k), v) - case _ => abort(s"$elem has the wrong shape for a record field") - } - - rec.foldRight(hnilValueTree) { (elem, acc) => - q"$hconsValueTree(${promoteElem(elem)}, $acc)" - } - } - - def mkParamsImpl[L <: HList](method: MethodSymbol, rec: Expr[L]): List[List[Tree]] = { - val selector = reify(ops.hlist.Selector) - def mkElem(key: Type, value: Tree): Tree = - q"$selector[${rec.actualType}, ${FieldType(key, value.tpe.widen)}].apply($rec)" - - method.paramLists.filterNot(_.forall(_.isImplicit)).map(_.map { p => - mkElem(constantType(nameAsValue(p.name)), q"${p.typeSignature}") - }) - } -} +trait FromRecordArgs extends Dynamic with FromRecordArgsScalaCompat diff --git a/core/src/main/scala/shapeless/singletons.scala b/core/src/main/scala/shapeless/singletons.scala index 71ddd4503..5591d8230 100644 --- a/core/src/main/scala/shapeless/singletons.scala +++ b/core/src/main/scala/shapeless/singletons.scala @@ -16,11 +16,7 @@ package shapeless -import shapeless.syntax.SingletonOps - import scala.language.dynamics -import scala.language.experimental.macros -import scala.reflect.macros.whitebox /** Provides the value corresponding to a singleton type. * @@ -31,7 +27,7 @@ trait Witness extends Serializable { val value: T {} } -object Witness extends Dynamic with WitnessInstances { +object Witness extends Dynamic with WitnessInstances with WitnessScalaCompat { type Aux[T0] = Witness { type T = T0 } type Lt[Lub] = Witness { type T <: Lub } @@ -45,9 +41,6 @@ object Witness extends Dynamic with WitnessInstances { implicit def witnessN[P <: Nat]: Witness.Aux[Succ[P]] = mkWitness(Succ[P]()) - - def selectDynamic(tpeSelector: String): Any = - macro SingletonTypeMacros.witnessTypeImpl } trait WitnessWith[TC[_]] extends Witness { @@ -64,15 +57,9 @@ trait NatWith[TC[_ <: Nat]] { val instance: TC[N] } -object NatWith { +object NatWith extends NatWithScalaCompat { type Aux[TC[_ <: Nat], N0 <: Nat] = NatWith[TC] { type N = N0 } - implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = - macro SingletonTypeMacros.convertInstanceImplNat[TC] - - implicit def apply2[B, T <: B, TC[_ <: B, _ <: Nat]](i: Int): NatWith[({ type λ[t <: Nat] = TC[T, t] })#λ] = - macro SingletonTypeMacros.convertInstanceImplNat1[B, T, TC] - def depInstance[TC[_ <: Nat] <: AnyRef, N0 <: Nat](tc: TC[N0]): Aux[TC, N0] { val instance: tc.type } = new NatWith[TC] { type N = N0 @@ -107,7 +94,7 @@ object NatWith { */ trait Widen[T] extends DepFn1[T] { type Out >: T } -object Widen { +object Widen extends WidenScalaCompat { def apply[T](implicit widen: Widen[T]): Aux[T, widen.Out] = widen type Aux[T, Out0 >: T] = Widen[T] { type Out = Out0 } @@ -117,215 +104,4 @@ object Widen { type Out = Out0 def apply(t: T) = f(t) } - - implicit def apply1[TC[_], T](t: T): WitnessWith.Lt[TC, T] = macro SingletonTypeMacros.convertInstanceImpl1[TC] - - implicit def materialize[T, Out]: Aux[T, Out] = macro SingletonTypeMacros.materializeWiden[T, Out] -} - -trait SingletonTypeUtils extends ReprTypes { - import c.universe._ - import internal._ - import decorators._ - - def singletonOpsTpe: Type = typeOf[syntax.SingletonOps] - - object SingletonType { - def unapply(value: Tree): Option[Type] = (value, value.tpe) match { - case (Literal(const), _) => Some(constantType(const)) - case (_, keyType @ SingleType(_, v)) if !v.isParameter && !isValueClass(v) => Some(keyType) - case (q"${sops: Tree}.narrow", _) if sops.tpe <:< singletonOpsTpe => - Some(sops.tpe.member(TypeName("T")).typeSignature) - case _ => None - } - } - - def narrowValue(value: Tree): (Type, Tree) = value match { - case Literal(const) => - val tpe = constantType(const) - (tpe, q"$value.asInstanceOf[$tpe]") - case _ => - (value.tpe, value) - } - - def parseLiteralType(typeStr: String): Option[Type] = for { - parsed <- util.Try(c.parse(typeStr)).toOption - checked <- Option(c.typecheck(parsed, silent = true)) - if checked.nonEmpty - tpe <- SingletonType.unapply(checked) - } yield tpe - - def parseStandardType(typeStr: String): Option[Type] = for { - parsed <- util.Try(c.parse(s"null.asInstanceOf[$typeStr]")).toOption - checked <- Option(c.typecheck(parsed, silent = true)) - if checked.nonEmpty - } yield checked.tpe - - def parseType(typeStr: String): Option[Type] = - parseStandardType(typeStr) orElse parseLiteralType(typeStr) - - def typeCarrier(tpe: Type): Literal = - mkTypeCarrier(tq"{ type T = $tpe }") - - def fieldTypeCarrier(tpe: Type): Literal = - mkTypeCarrier(tq"""{ - type T = $tpe - type ->>[V] = Field[V] - type Field[V] = _root_.shapeless.labelled.FieldType[$tpe, V] - }""") - - def mkTypeCarrier(tree: Tree): Literal = { - val carrier = c.typecheck(tree, mode = c.TYPEmode).tpe - - // We can't yield a useful value here, so return Unit instead which is at least guaranteed - // to result in a runtime exception if the value is used in term position. - Literal(Constant(())).setType(carrier) - } - - def isValueClass(sym: Symbol): Boolean = { - val tSym = sym.typeSignature.typeSymbol - tSym.isClass && tSym.asClass.isDerivedValueClass - } -} - -class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { - import c.universe._ - import definitions._ - import internal._ - - def mkWitness(sTpe: Type, s: Tree): Tree = - q"${reify(Witness)}.mkWitness[$sTpe]($s.asInstanceOf[$sTpe])" - - def mkWitnessWith(tcTpe: Type, sTpe: Type, s: Tree, i: Tree): Tree = { - val witnessWith = reify(WitnessWith) - if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$witnessWith.depInstance[$tcTpe, $sTpe]($s, $i)" - else q"$witnessWith.instance[$tcTpe, $sTpe]($s, $i)" - } - - def mkWitnessNat(tcTpe: Type, nTpe: Type, tc: Tree): Tree = { - val natWith = reify(NatWith) - if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$natWith.depInstance[$tcTpe, $nTpe]($tc)" - else q"$natWith.instance[$tcTpe, $nTpe]($tc)" - } - - def mkOps(sTpe: Type, w: Tree): Tree = - q"${reify(SingletonOps)}.instance[$sTpe]($w)" - - def mkAttributedQualifier(tpe: Type): Tree = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gTpe = tpe.asInstanceOf[global.Type] - global.gen.mkAttributedQualifier(gTpe).asInstanceOf[Tree] - } - - @annotation.tailrec - final def unrefine(tpe: Type): Type = tpe.dealias match { - case RefinedType(List(parent), scope) if scope.isEmpty => unrefine(parent) - case other => other - } - - def extractSingletonValue(tpe: Type): Tree = unrefine(tpe) match { - case ConstantType(const) => Literal(const) - case singleton: SingleType => mkAttributedQualifier(singleton) - case ThisType(sym) => This(sym) - case ref @ TypeRef(_, sym, _) if sym.isModuleClass => mkAttributedQualifier(ref) - case _ => c.abort(c.enclosingPosition, s"Type argument $tpe is not a singleton type") - } - - def materializeImpl[T: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T].dealias - mkWitness(tpe, extractSingletonValue(tpe)) - } - - def extractResult(value: Tree)(mkResult: (Type, Tree) => Tree): Tree = - (value.tpe, value) match { - case (tpe @ ConstantType(const), _) => - mkResult(tpe, Literal(const)) - - case (tpe: SingleType, tree) => - mkResult(tpe, tree) - - case (_, tree: This) => - mkResult(thisType(tree.symbol), tree) - - case (_, tree) if (tree.symbol ne null) && tree.symbol.isTerm && tree.symbol.asTerm.isStable => - val sym = tree.symbol.asTerm - val pre = if (sym.owner.isClass) thisType(sym.owner) else NoPrefix - val symTpe = singleType(pre, sym) - mkResult(symTpe, q"$sym.asInstanceOf[$symTpe]") - - case _ => - c.abort(c.enclosingPosition, s"Expression $value does not evaluate to a constant or a stable reference value") - } - - def convertImpl(t: Tree): Tree = extractResult(t)(mkWitness) - - def inferInstance(tci: Type): Tree = { - val inferred = c.inferImplicitValue(tci) - if (inferred == EmptyTree) - c.abort(c.enclosingPosition, s"Unable to resolve implicit value of type $tci") - inferred - } - - def convertInstanceImplNat[TC[_ <: Nat]](i: Tree)( - implicit tcTag: WeakTypeTag[TC[Nothing]] - ): Tree = convertInstanceImplNatAux(i, tcTag.tpe) - - def convertInstanceImplNat1[B, T <: B, TC[_ <: B, _ <: Nat]](i: Tree)( - implicit tTag: WeakTypeTag[T], tcTag: WeakTypeTag[TC[Nothing, Nothing]] - ): Tree = { - val tTpe = tTag.tpe - val tc = tcTag.tpe.typeConstructor - val tcParam = tc.typeParams(1) - val tcTpe = polyType(List(tcParam), appliedType(tc, tTpe, tcParam.asType.toType)) - convertInstanceImplNatAux(i, tcTpe) - } - - def convertInstanceImplNatAux(i: Tree, tcTpe: Type): Tree = { - val nTpe = i match { - case NatLiteral(n) => mkNatTpe(n) - case _ => c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") - } - - val instTpe = appliedType(tcTpe, nTpe) - val iInst = inferInstance(instTpe) - mkWitnessNat(tcTpe, nTpe, iInst) - } - - def convertInstanceImpl1[TC[_]](t: Tree)( - implicit tcTag: WeakTypeTag[TC[_]] - ): Tree = extractResult(t) { (sTpe, value) => - val tc = tcTag.tpe.typeConstructor - val tci = appliedType(tc, sTpe) - val i = inferInstance(tci) - mkWitnessWith(tc, sTpe, value, i) - } - - def convertInstanceImpl2[H, TC2[_ <: H, _], S <: H](t: Tree)( - implicit tc2Tag: WeakTypeTag[TC2[_, _]], sTag: WeakTypeTag[S] - ): Tree = extractResult(t) { (sTpe, value) => - val tc2 = tc2Tag.tpe.typeConstructor - val tparam = tc2.typeParams.last.asType - val tc = polyType(tparam :: Nil, appliedType(tc2, sTag.tpe, tparam.toType)) - val tci = appliedType(tc2, sTag.tpe, sTpe) - val i = inferInstance(tci) - mkWitnessWith(tc, sTpe, value, i) - } - - def mkSingletonOps(t: Tree): Tree = - extractResult(t) { (tpe, tree) => mkOps(tpe, mkWitness(tpe, tree)) } - - def witnessTypeImpl(tpeSelector: Tree): Tree = { - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val tpe = parseLiteralType(tpeString) - .getOrElse(c.abort(c.enclosingPosition, s"Malformed literal $tpeString")) - - fieldTypeCarrier(tpe) - } - - def materializeWiden[T: WeakTypeTag, Out: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T].dealias - val wideTpe = tpe.widen - if (wideTpe =:= tpe) c.abort(c.enclosingPosition, s"Don't know how to widen $tpe") - else q"${reify(Widen)}.instance[$tpe, $wideTpe](${reify(Predef)}.identity)" - } } diff --git a/core/src/main/scala/shapeless/syntax/sized.scala b/core/src/main/scala/shapeless/syntax/sized.scala index a93a0a682..ab9333312 100644 --- a/core/src/main/scala/shapeless/syntax/sized.scala +++ b/core/src/main/scala/shapeless/syntax/sized.scala @@ -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]) { diff --git a/core/src/main/scala/shapeless/syntax/std/functions.scala b/core/src/main/scala/shapeless/syntax/std/functions.scala index 5aa6e1e39..0c1ae3189 100644 --- a/core/src/main/scala/shapeless/syntax/std/functions.scala +++ b/core/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/src/main/scala/shapeless/syntax/std/maps.scala b/core/src/main/scala/shapeless/syntax/std/maps.scala index 65cf90fd7..ba85c3b4e 100644 --- a/core/src/main/scala/shapeless/syntax/std/maps.scala +++ b/core/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/src/main/scala/shapeless/syntax/std/traversables.scala b/core/src/main/scala/shapeless/syntax/std/traversables.scala index 1e1a6e720..be24090b7 100644 --- a/core/src/main/scala/shapeless/syntax/std/traversables.scala +++ b/core/src/main/scala/shapeless/syntax/std/traversables.scala @@ -28,14 +28,14 @@ package std * @author Rob Norris */ object traversable { - implicit def traversableOps[T](t : T)(implicit ev: T => Iterable[_]) = new TraversableOps(t) - implicit def traversableOps2[CC[T] <: Iterable[T], A](as: CC[A]) = new TraversableOps2(as) + implicit def traversableOps[T](t : T)(implicit ev: T => Iterable[_]): TraversableOps[T] = new TraversableOps(t) + implicit def traversableOps2[CC[T] <: Iterable[T], A](as: CC[A]): TraversableOps2[CC, A] = new TraversableOps2(as) } final class TraversableOps[T](t : T)(implicit ev: T => Iterable[_]) { import ops.traversable._ - def toHList[L <: HList](implicit fl : FromTraversable[L]) : Option[L] = fl(t) + def toHList[L <: HList](implicit fl : FromTraversable[L]) : Option[L] = fl(ev(t)) } final class TraversableOps2[CC[T] <: Iterable[T], A](as: CC[A]) { diff --git a/core/src/main/scala/shapeless/syntax/zipper.scala b/core/src/main/scala/shapeless/syntax/zipper.scala index 1fb1eb5bf..1de1c3062 100644 --- a/core/src/main/scala/shapeless/syntax/zipper.scala +++ b/core/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/src/main/scala/shapeless/typeable.scala b/core/src/main/scala/shapeless/typeable.scala index 32fda4382..b86c483bc 100644 --- a/core/src/main/scala/shapeless/typeable.scala +++ b/core/src/main/scala/shapeless/typeable.scala @@ -16,10 +16,6 @@ package shapeless -import scala.language.experimental.macros - -import scala.reflect.macros.blackbox - /** * Type class supporting type safe cast. * @@ -31,9 +27,7 @@ trait Typeable[T] extends Serializable { override def toString = s"Typeable[$describe]" } -trait LowPriorityTypeable { - implicit def dfltTypeable[T]: Typeable[T] = macro TypeableMacros.dfltTypeableImpl[T] -} +trait LowPriorityTypeable extends LowPriorityTypeableScalaCompat /** * Provides instances of `Typeable`. Also provides an implicit conversion which enhances arbitrary values with a @@ -197,7 +191,7 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { // Nb. the apparently redundant `with Iterable[T]` is a workaround for a // Scala bug which causes conflicts between this instance and `anyTypeable`. implicit def genTraversableTypeable[CC[X] <: Iterable[X], T]( - implicit mCC: ClassTag[CC[_]], castT: Typeable[T] + implicit mCC: ClassTag[CC[Any]], castT: Typeable[T] ): Typeable[CC[T] with Iterable[T]] = instance(s"${safeSimpleName(mCC)}[${castT.describe}]") { t => if (t == null) None else if (mCC.runtimeClass isInstance t) { @@ -208,7 +202,7 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { /** Typeable instance for `Map`. Note that the contents will be tested for conformance to the key/value types. */ implicit def genMapTypeable[M[X, Y], K, V]( - implicit ev: M[K, V] <:< Map[K, V], mM: ClassTag[M[_, _]], castK: Typeable[K], castV: Typeable[V] + implicit ev: M[K, V] <:< Map[K, V], mM: ClassTag[M[Any, Any]], castK: Typeable[K], castV: Typeable[V] ): Typeable[M[K, V]] = instance(s"${safeSimpleName(mM)}[${castK.describe}, ${castV.describe}]") { t => if (t == null) None else if (mM.runtimeClass isInstance t) { @@ -225,9 +219,10 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { - val c = t.asInstanceOf[Product with T] - val f = c.productIterator.toList - if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(c) else None + val cp = t.asInstanceOf[Product] + val ct = t.asInstanceOf[T] + val f = cp.productIterator.toList + if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None } else None } @@ -305,128 +300,3 @@ object TypeCase { override def toString = s"TypeCase[${tt.describe}]" } } - -class TypeableMacros(val c: blackbox.Context) extends SingletonTypeUtils { - import c.universe._ - import definitions.NothingClass - - val typeableTpe: Type = typeOf[Typeable[_]].typeConstructor - val genericTpe: Type = typeOf[Generic[_]].typeConstructor - - def dfltTypeableImpl[T: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T] - val dealiased = tpe.dealias - - dealiased match { - case t: TypeRef if t.sym == NothingClass => - c.abort(c.enclosingPosition, "No Typeable for Nothing") - - case ExistentialType(_, _) => - val tArgs = dealiased.typeArgs - val normalized = appliedType(dealiased.typeConstructor, tArgs) - val normalizedTypeable = c.inferImplicitValue(appliedType(typeableTpe, List(normalized))) - if (normalizedTypeable.isEmpty) - c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") - normalizedTypeable - - case RefinedType(parents, decls) => - if (decls.nonEmpty) - c.abort(c.enclosingPosition, "No Typeable for a refinement with non-empty decls") - val parentTypeables = parents.filterNot(_ =:= typeOf[AnyRef]).map { parent => - c.inferImplicitValue(appliedType(typeableTpe, List(parent))) - } - if (parentTypeables.exists(_.isEmpty)) - c.abort(c.enclosingPosition, "Missing Typeable for parent of a refinement") - - q"""_root_.shapeless.Typeable.intersectionTypeable( - _root_.scala.Array[_root_.shapeless.Typeable[_]](..$parentTypeables) - )""" - - case pTpe if pTpe.typeArgs.nonEmpty => - val pSym = { - val sym = pTpe.typeSymbol - if (!sym.isClass) - c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") - - val pSym0 = sym.asClass - pSym0.typeSignature // Workaround for - - pSym0 - } - - if(!pSym.isCaseClass) - c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") - else - mkCaseClassTypeable(tpe) - - case SingleType(_, v) if !v.isParameter => - q"""_root_.shapeless.Typeable.referenceSingletonTypeable[$tpe]( - $v.asInstanceOf[$tpe], ${nameOf(v)}, serializable = ${v.isModule} - )""" - - case ConstantType(c) => - q"""_root_.shapeless.Typeable.valueSingletonTypeable[$tpe]($c.asInstanceOf[$tpe], ${nameOf(c.tpe)})""" - - // Outer#Inner is unsound in general since Inner can capture type members of Outer. - case TypeRef(TypeRef(_, outer, args), inner, _) if !outer.isFinal || args.nonEmpty => - if (inner.isClass && inner.asClass.isCaseClass) mkCaseClassTypeable(tpe) - else c.abort(c.enclosingPosition, s"No default Typeable for type projection $tpe") - - case _ => - val tsym = tpe.typeSymbol - if (tsym.isStatic || tsym.isFinal || (tsym.isClass && tsym.asClass.isTrait)) { - // scala/bug#4440 Final inner classes and traits have no outer accessor. - q"_root_.shapeless.Typeable.namedSimpleTypeable(_root_.scala.Predef.classOf[$tpe], ${nameOf(tsym)})" - } else { - q"_root_.shapeless.Typeable.partialFunctionTypeable({ case x: $tpe => x }, ${nameOf(tsym)})" - } - } - } - - private def mkCaseClassTypeable(tpe: Type): Tree = { - // an unsafe accessor is one that isn't a case class accessor but has an abstract type. - def isUnsafeAccessor(sym: TermSymbol): Boolean = { - - if (sym.isCaseAccessor) { - false - } else { - val symType = sym.typeSignature.typeSymbol - val isAbstract = - symType.isAbstract || // Under Scala 2.10, isAbstract is spuriously false (macro-compat issue?) - (symType != NoSymbol && symType.owner == tpe.typeSymbol) // So check the owner as well - - if (isAbstract) { - sym.isVal || - sym.isVar || - (sym.isParamAccessor && !(sym.accessed.isTerm && sym.accessed.asTerm.isCaseAccessor)) - } else false - } - } - - val nonCaseAccessor = tpe.decls.exists { - case sym: TermSymbol if isUnsafeAccessor(sym) => true - case _ => false - } - if (nonCaseAccessor) { - // there is a symbol, which is not a case accessor but a val, - // var or param, so we won't be able to type check it safely: - c.abort(c.enclosingPosition, s"No default Typeable for parametrized type $tpe") - } - val fields = tpe.decls.sorted collect { - case sym: TermSymbol if sym.isVal && sym.isCaseAccessor => sym.typeSignatureIn(tpe) - } - val fieldTypeables = fields.map { field => c.inferImplicitValue(appliedType(typeableTpe, List(field))) } - if(fieldTypeables.contains(EmptyTree)) - c.abort(c.enclosingPosition, "Missing Typeable for field of a case class") - - q""" _root_.shapeless.Typeable.namedCaseClassTypeable( - _root_.scala.Predef.classOf[$tpe], _root_.scala.Array[_root_.shapeless.Typeable[_]](..$fieldTypeables), ${nameOf(tpe)} - )""" - } - - private def nameOf(sym: Symbol): String = - sym.name.decodedName.toString - - private def nameOf(tpe: Type): String = - nameOf(tpe.typeSymbol) -} diff --git a/core/src/main/scala/shapeless/typeoperators.scala b/core/src/main/scala/shapeless/typeoperators.scala index 98e731db4..018509b43 100644 --- a/core/src/main/scala/shapeless/typeoperators.scala +++ b/core/src/main/scala/shapeless/typeoperators.scala @@ -17,10 +17,6 @@ package shapeless import scala.language.dynamics -import scala.language.experimental.macros - -import scala.reflect.macros.whitebox -import scala.util.{ Try, Success, Failure } object tag { def apply[U] = Tagger.asInstanceOf[Tagger[U]] @@ -56,7 +52,7 @@ object newtype { * The implicit conversion `Repr => Ops` would typically be provided by publishing the companion * object of the `Ops` type as an implicit value. */ - implicit def newtypeOps[Repr, Ops](t : Newtype[Repr, Ops])(implicit mkOps : Repr => Ops) : Ops = t.asInstanceOf[Repr] + implicit def newtypeOps[Repr, Ops](t : Newtype[Repr, Ops])(implicit mkOps : Repr => Ops) : Ops = mkOps(t.asInstanceOf[Repr]) } /** @@ -106,82 +102,9 @@ object newtype { * i: Int = 23 * }}} */ -object the extends Dynamic { - def apply[T](implicit t: T): T = macro TheMacros.applyImpl - - def selectDynamic(tpeSelector: String): Any = macro TheMacros.implicitlyImpl -} - -class TheMacros(val c: whitebox.Context) { - import c.universe.{ Try => _, _ } - import internal._, decorators._ - - def applyImpl(t: Tree): Tree = t - - def implicitlyImpl(tpeSelector: Tree): Tree = { +object the extends Dynamic with theScalaCompat - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val dummyNme = c.freshName() - - val tpe = - (for { - parsed <- Try(c.parse(s"{ type $dummyNme = "+tpeString+" }")).toOption - checked = c.typecheck(parsed, silent = true) - if checked.nonEmpty - } yield { - val q"{ type $dummyNme = $tpt }" = (checked: @unchecked) - tpt.tpe - }).getOrElse(c.abort(c.enclosingPosition, s"Malformed type $tpeString")) - - // Bail for primitives because the resulting trees with type set to Unit - // will crash the compiler - if(tpe.typeSymbol.asClass.isPrimitive) - c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context") - - - Try(c.typecheck(q"_root_.shapeless.the.apply[$tpe]")) match { - case Success(x) => - // We can't yield a useful value here, so return Unit instead which is at least guaranteed - // to result in a runtime exception if the value is used in term position. - Literal(Constant(())).setType(x.tpe) - case Failure(e) => c.abort(c.enclosingPosition, e.getMessage) - } - } -} - - -object TypeOf extends Dynamic { - - def selectDynamic(code: String): Any = macro Macros.selectDynamic - - private[TypeOf] final class Macros(val c: whitebox.Context) { - import c.universe.{Try => _, _} - import internal._, decorators._ - - def selectDynamic(code: Tree): Tree = { - - val q"${codeString: String}" = (code: @unchecked) - val tpe = c.parse(codeString) match { - case Typed(expr, tpt) => - val baseType = c.typecheck(tpt, mode = c.TYPEmode) - c.typecheck(expr, pt = baseType.tpe).tpe - case expr => - c.typecheck(expr).tpe - } - - // Bail for primitives because the resulting trees with type set to Unit - // will crash the compiler - val symbol = tpe.typeSymbol - if (symbol.isClass && symbol.asClass.isPrimitive) - c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context") - - // We can't yield a useful value here, so return Unit instead which is at least guaranteed - // to result in a runtime exception if the value is used in term position. - Literal(Constant(())).setType(tpe) - } - } - -} +object TypeOf extends Dynamic with TypeOfScalaCompat /** * Type class witnessing the least upper bound of a pair of types and providing conversions from each to their common @@ -195,7 +118,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/src/main/scala/shapeless/unions.scala b/core/src/main/scala/shapeless/unions.scala index 50b303afe..01b78c3fc 100644 --- a/core/src/main/scala/shapeless/unions.scala +++ b/core/src/main/scala/shapeless/unions.scala @@ -17,9 +17,6 @@ package shapeless import scala.language.dynamics -import scala.language.experimental.macros - -import scala.reflect.macros.whitebox object union { import syntax.UnionOps @@ -50,41 +47,5 @@ object union { * y.get("y") // == Some("foo") * }}} */ - object Union extends Dynamic { - def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = macro UnionMacros.mkUnionNamedImpl[U] - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.unionType - } -} - -class UnionMacros(val c: whitebox.Context) { - import c.universe._ - import internal.constantType - import labelled.FieldType - - def mkUnionNamedImpl[U <: Coproduct : WeakTypeTag](method: Tree)(elems: Tree*): Tree = { - val fieldTypeTpe = typeOf[FieldType[_, _]].typeConstructor - val coproduct = reify(Coproduct) - - def mkFieldTpe(keyTpe: Type, valueTpe: Type): Type = - appliedType(fieldTypeTpe, List(keyTpe, valueTpe.widen)) - - def mkElem(keyTpe: Type, value: Tree): Tree = - q"$value.asInstanceOf[${mkFieldTpe(keyTpe, value.tpe)}]" - - def promoteElem(elem: Tree): Tree = elem match { - case q"$_(${Literal(k)}, $v)" => mkElem(constantType(k), v) - case _ => c.abort(c.enclosingPosition, s"$elem has the wrong shape for a record field") - } - - val q"${methodString: String}" = (method: @unchecked) - if (methodString != "apply") - c.abort(c.enclosingPosition, s"this method must be called as 'apply' not '$methodString'") - - val elem = elems match { - case Seq(e) => e - case _ => c.abort(c.enclosingPosition, "only one branch of a union may be inhabited") - } - - q"$coproduct[${weakTypeOf[U]}](${promoteElem(elem)})" - } + object Union extends Dynamic with UnionScalaCompat } diff --git a/core/src/main/scala/shapeless/unwrapped.scala b/core/src/main/scala/shapeless/unwrapped.scala index bedf51ada..140a4c504 100644 --- a/core/src/main/scala/shapeless/unwrapped.scala +++ b/core/src/main/scala/shapeless/unwrapped.scala @@ -17,6 +17,7 @@ package shapeless import newtype._ +import shapeless.Unwrapped.Aux trait Unwrapped[W] extends Serializable { type U @@ -34,7 +35,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 +48,7 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { } object AnyValHelper { type Aux[Repr, U0] = AnyValHelper[Repr] { type U = U0 } - implicit def sizeOneHListHelper[T] = + implicit def sizeOneHListHelper[T]: AnyValHelper.Aux[T :: HNil, T] = SizeOneHListHelper.asInstanceOf[AnyValHelper.Aux[T :: HNil, T]] val SizeOneHListHelper = new AnyValHelper[Any :: HNil] { type U = Any @@ -58,11 +59,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]] + ): 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]] + ): Aux[T[UI, TT], UF] = chain.value.asInstanceOf[Unwrapped.Aux[T[UI, TT], UF]] } @@ -73,6 +74,6 @@ trait LowPriorityUnwrappedInstances { def unwrap(t: Any) = t def wrap(t: Any) = t } - implicit def selfUnwrapped[T] = + implicit def selfUnwrapped[T]: Aux[T, T] = theSelfUnwrapped.asInstanceOf[Unwrapped.Aux[T, T]] } diff --git a/core/src/main/scala_2.13+/shapeless/versionspecifics.scala b/core/src/main/scala_2.13+/shapeless/versionspecifics.scala index cedc69fff..f5b406949 100644 --- a/core/src/main/scala_2.13+/shapeless/versionspecifics.scala +++ b/core/src/main/scala_2.13+/shapeless/versionspecifics.scala @@ -16,6 +16,7 @@ package shapeless +import scala.language.experimental.macros import scala.reflect.macros.whitebox trait LazyInstances { @@ -59,6 +60,8 @@ trait ScalaVersionSpecifics { s"Implicit value of type $tpe not found" } } + + def cachedImplicit[T]: T = macro CachedImplicitMacros.cachedImplicitImpl[T] } trait CaseClassMacrosVersionSpecifics { self: CaseClassMacros => diff --git a/core/src/main/scala_2.13-/shapeless/versionspecifics.scala b/core/src/main/scala_2.13-/shapeless/versionspecifics.scala index 99e9b2dbe..fb38fa0fc 100644 --- a/core/src/main/scala_2.13-/shapeless/versionspecifics.scala +++ b/core/src/main/scala_2.13-/shapeless/versionspecifics.scala @@ -115,6 +115,8 @@ trait ScalaVersionSpecifics extends LP0 { private[shapeless] implicit class NewIsIterable0[A0, Repr](itl: IsRegularIterable[Repr] { type A = A0 }) { def apply(r: Repr): GenTraversableLike[A0, Repr] = itl.conversion(r) } + + def cachedImplicit[T]: T = macro CachedImplicitMacros.cachedImplicitImpl[T] } trait LP0 extends LP1 { diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala index a2b959f21..6e10748b9 100644 --- a/project/Boilerplate.scala +++ b/project/Boilerplate.scala @@ -388,7 +388,7 @@ object Boilerplate { - object build extends Poly${arity} { - val functions = self.functions - implicit def allCases[${`A..N`}, Out](implicit tL: Function${arity}TypeAt[${`A..N`}, Out, HL]): Case.Aux[${`A..N`}, Out] = - - at(tL(functions)) + - this.at(tL(functions)) - } - } - From bcf78cd0ceb3819d69edc3534310a05f71a4b970 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 21:56:40 +0200 Subject: [PATCH 02/32] Drop support for Scala 2.12 --- build.sbt | 40 +- .../shapeless/versionspecifics.scala | 30 -- .../scala-3/shapeless/versionspecifics.scala | 30 -- core/src/main/scala/shapeless/coproduct.scala | 3 +- core/src/main/scala/shapeless/lazy.scala | 8 +- core/src/main/scala/shapeless/package.scala | 2 + .../src/main/scala/shapeless/singletons.scala | 20 +- .../scala/shapeless/syntax/singletons.scala | 5 + .../shapeless/syntax/singleton.scala | 8 - .../scala_2.13-/shapeless/LazyMacros.scala | 370 ------------------ .../shapeless/syntax/singleton.scala | 10 - .../shapeless/versionspecifics.scala | 151 ------- plugin/src/main/resources/scalac-plugin.xml | 4 - .../shapeless/ShapelessPlugin.scala | 86 ---- .../shapeless/ShapelessPlugin.scala | 66 ---- 15 files changed, 40 insertions(+), 793 deletions(-) rename core/src/main/{scala_2.13+ => scala-2}/shapeless/versionspecifics.scala (62%) delete mode 100644 core/src/main/scala_2.13+/shapeless/syntax/singleton.scala delete mode 100644 core/src/main/scala_2.13-/shapeless/LazyMacros.scala delete mode 100644 core/src/main/scala_2.13-/shapeless/syntax/singleton.scala delete mode 100644 core/src/main/scala_2.13-/shapeless/versionspecifics.scala delete mode 100644 plugin/src/main/resources/scalac-plugin.xml delete mode 100644 plugin/src/main/scala_2.13+/shapeless/ShapelessPlugin.scala delete mode 100644 plugin/src/main/scala_2.13-/shapeless/ShapelessPlugin.scala diff --git a/build.sbt b/build.sbt index 9cb9f32cf..58c578a96 100644 --- a/build.sbt +++ b/build.sbt @@ -1,7 +1,6 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject -val Scala212 = "2.12.14" val Scala213 = "2.13.6" val scala3 = "3.0.0" @@ -11,7 +10,7 @@ crossScalaVersions := Nil ThisBuild / organization := "com.chuusai" ThisBuild / scalaVersion := Scala213 -ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, scala3) +ThisBuild / crossScalaVersions := Seq(Scala213, scala3) ThisBuild / mimaFailOnNoPrevious := false // GHA configuration @@ -76,24 +75,14 @@ val scalacOptionsAll = List( "-unchecked" ) -def scalacOptions2(pluginJar: File) = List( - s"-Xplugin:${pluginJar.getAbsolutePath}", - s"-Jdummy=${pluginJar.lastModified}" -) - val scalacOptions3 = Seq( "-language:dynamics", ) -def scalacOptions212(pluginJar: File) = Seq( - "-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,_", - "-Ywarn-unused:-implicits" -) ++ scalacOptions2(pluginJar) - -def scalacOptions213(pluginJar: File) = Seq( +val scalacOptions213 = Seq( "-Xlint:-adapted-args,-delayedinit-select,-nullary-unit,-package-object-classes,-type-parameter-shadow,-byname-implicit,_", "-Ywarn-unused:-implicits" -) ++ scalacOptions2(pluginJar) +) lazy val commonSettings = Seq( incOptions := incOptions.value.withLogRecompileOnMacro(false), @@ -101,8 +90,7 @@ lazy val commonSettings = Seq( scalacOptions := scalacOptionsAll, Compile / compile / scalacOptions ++= (CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 12)) => scalacOptions212((plugin / Compile / packageBin).value) - case Some((2, 13)) => scalacOptions213((plugin / Compile / packageBin).value) + case Some((2, 13)) => scalacOptions213 case Some((3, _)) => scalacOptions3 case _ => Nil }), @@ -164,17 +152,6 @@ lazy val CrossTypeMixed: sbtcrossproject.CrossType = new sbtcrossproject.CrossTy Some(projectBase.getParentFile / "src" / conf / "scala") } -lazy val plugin = project.in(file("plugin")) - .settings(crossVersionSharedSources) - .settings(publishSettings) - .settings( - name := "shapeless-plugin", - moduleName := "shapeless-plugin", - sbtPlugin := true, - scalaVersion := Scala213, - crossScalaVersions := Seq(Scala213, Scala212) - ) - lazy val core = crossProject(JSPlatform, JVMPlatform/* TODO, NativePlatform*/).crossType(CrossTypeMixed) .configureCross(configureJUnit) .settings(moduleName := "shapeless") @@ -290,18 +267,17 @@ lazy val scalaMacroDependencies: Def.Initialize[Seq[ModuleID]] = Def.setting { lazy val crossVersionSharedSources: Seq[Setting[_]] = Seq(Compile, Test).map { sc => - (sc / unmanagedSourceDirectories) ++= { + (sc / unmanagedSourceDirectories) := { (sc / unmanagedSourceDirectories).value.flatMap { dir: File => //Seems like cross projects don't get this source folder as well TODO: Make an issue for it - val scala2Folder = new File(dir.getPath + "-2") + val scala2Folder = file(dir.getPath + "-2") if (dir.getName != "scala") Seq(dir) else CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, y)) if y >= 13 => Seq(new File(dir.getPath + "_2.13+"), scala2Folder) - case Some((2, y)) if y < 13 => Seq(new File(dir.getPath + "_2.13-"), scala2Folder) + case Some((2, _)) => Seq(dir, scala2Folder) case _ => Seq(dir) } - } + }.distinct } } diff --git a/core/src/main/scala_2.13+/shapeless/versionspecifics.scala b/core/src/main/scala-2/shapeless/versionspecifics.scala similarity index 62% rename from core/src/main/scala_2.13+/shapeless/versionspecifics.scala rename to core/src/main/scala-2/shapeless/versionspecifics.scala index f5b406949..c0851c6c6 100644 --- a/core/src/main/scala_2.13+/shapeless/versionspecifics.scala +++ b/core/src/main/scala-2/shapeless/versionspecifics.scala @@ -19,37 +19,7 @@ package shapeless import scala.language.experimental.macros import scala.reflect.macros.whitebox -trait LazyInstances { - implicit def mkLazy[I](implicit i: => I): Lazy[I] = Lazy(i) -} - -trait StrictInstances { - implicit def mkStrict[I](implicit i: I): Strict[I] = Strict(i) -} - -trait WitnessInstances { - implicit def of[T: ValueOf]: Witness.Aux[T] = - Witness.mkWitness(valueOf[T]) - - implicit def apply[T](t: T): Witness.Aux[t.type] = - Witness.mkWitness[t.type](t) -} - -trait WitnessWithInstances { - implicit def apply[TC[_], T](t: T)(implicit tc: TC[t.type]): WitnessWith.Aux[TC, t.type] { val instance: tc.type } = - instance[TC, t.type](t, tc) - - def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = - new WitnessWith[TC] { - type T = A - val value: T = v - val instance: tc.type = tc - } -} - trait ScalaVersionSpecifics { - private[shapeless] type IsRegularIterable[Repr] = collection.generic.IsIterable[Repr] { type C = Repr } - private[shapeless] def implicitNotFoundMessage(c: whitebox.Context)(tpe: c.Type): String = { val global = c.universe.asInstanceOf[scala.tools.nsc.Global] val gTpe = tpe.asInstanceOf[global.Type] diff --git a/core/src/main/scala-3/shapeless/versionspecifics.scala b/core/src/main/scala-3/shapeless/versionspecifics.scala index 8eba3848d..9c36ec6f9 100644 --- a/core/src/main/scala-3/shapeless/versionspecifics.scala +++ b/core/src/main/scala-3/shapeless/versionspecifics.scala @@ -16,36 +16,6 @@ package shapeless -trait LazyInstances { - implicit def mkLazy[I](implicit i: => I): Lazy[I] = Lazy(i) -} - -trait StrictInstances { - implicit def mkStrict[I](implicit i: I): Strict[I] = Strict(i) -} - -trait WitnessInstances { - implicit def of[T: ValueOf]: Witness.Aux[T] = - Witness.mkWitness(valueOf[T]) - - implicit def apply[T](t: T): Witness.Aux[t.type] = - Witness.mkWitness[t.type](t) -} - -trait WitnessWithInstances { - implicit def apply[TC[_], T](t: T)(implicit tc: TC[t.type]): WitnessWith.Aux[TC, t.type] { val instance: tc.type } = - instance[TC, t.type](t, tc) - - def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = - new WitnessWith[TC] { - type T = A - val value: T = v - val instance: tc.type = tc - } -} - trait ScalaVersionSpecifics { - private[shapeless] type IsRegularIterable[Repr] = collection.generic.IsIterable[Repr] { type C = Repr } - def cachedImplicit[T]: T = ??? } diff --git a/core/src/main/scala/shapeless/coproduct.scala b/core/src/main/scala/shapeless/coproduct.scala index 1307c4e5d..8f186213e 100644 --- a/core/src/main/scala/shapeless/coproduct.scala +++ b/core/src/main/scala/shapeless/coproduct.scala @@ -135,10 +135,9 @@ object Coproduct extends Dynamic with CoproductScalaCompat { (0 until length).foldLeft[Coproduct](Inl(value))((accum, _) => Inr(accum)) @tailrec - def unsafeGet(c: Coproduct): Any = c match { + def unsafeGet(c: Coproduct): Any = (c: @unchecked) match { case Inl(h) => h case Inr(c) => unsafeGet(c) - case nil: CNil => nil.impossible } /** Allows to inject a runtime value of type `Any` in a `Coproduct` */ diff --git a/core/src/main/scala/shapeless/lazy.scala b/core/src/main/scala/shapeless/lazy.scala index 234f8d468..a29f10a2b 100644 --- a/core/src/main/scala/shapeless/lazy.scala +++ b/core/src/main/scala/shapeless/lazy.scala @@ -111,12 +111,14 @@ trait Lazy[+T] extends Serializable with LazyScalaCompat[T] { def flatMap[U](f: T => Lazy[U]): Lazy[U] = Lazy { f(value).value } } -object Lazy extends LazyInstances { +object Lazy { implicit def apply[T](t: => T): Lazy[T] = new Lazy[T] { lazy val value: T = t } + implicit def mkLazy[I](implicit i: => I): Lazy[I] = Lazy(i) + def unapply[T](lt: Lazy[T]): Option[T] = Some(lt.value) @implicitNotFound("could not find Lazy implicit values for all of the types enumerated in ${T}") @@ -150,11 +152,13 @@ trait Strict[+T] extends Serializable { def flatMap[U](f: T => Strict[U]): Strict[U] = Strict { f(value).value } } -object Strict extends StrictInstances { +object Strict { implicit def apply[T](t: T): Strict[T] = new Strict[T] { val value: T = t } + implicit def mkStrict[I](implicit i: I): Strict[I] = Strict(i) + def unapply[T](lt: Strict[T]): Option[T] = Some(lt.value) } diff --git a/core/src/main/scala/shapeless/package.scala b/core/src/main/scala/shapeless/package.scala index b72f23e7f..5de8ced95 100644 --- a/core/src/main/scala/shapeless/package.scala +++ b/core/src/main/scala/shapeless/package.scala @@ -103,4 +103,6 @@ package object shapeless extends ScalaVersionSpecifics { def everywhere[T, R](f: Poly)(t: T)( implicit cse: => Case1.Aux[EverywhereAux[f.type], T, R] ): R = cse(t) + + private[shapeless] type IsRegularIterable[Repr] = collection.generic.IsIterable[Repr] { type C = Repr } } diff --git a/core/src/main/scala/shapeless/singletons.scala b/core/src/main/scala/shapeless/singletons.scala index 5591d8230..60f6def28 100644 --- a/core/src/main/scala/shapeless/singletons.scala +++ b/core/src/main/scala/shapeless/singletons.scala @@ -27,7 +27,7 @@ trait Witness extends Serializable { val value: T {} } -object Witness extends Dynamic with WitnessInstances with WitnessScalaCompat { +object Witness extends Dynamic with WitnessScalaCompat { type Aux[T0] = Witness { type T = T0 } type Lt[Lub] = Witness { type T <: Lub } @@ -36,6 +36,12 @@ object Witness extends Dynamic with WitnessInstances with WitnessScalaCompat { val value = v } + implicit def of[T: ValueOf]: Witness.Aux[T] = + Witness.mkWitness(valueOf[T]) + + implicit def apply[T](t: T): Witness.Aux[t.type] = + Witness.mkWitness[t.type](t) + implicit val witness0: Witness.Aux[_0] = mkWitness(Nat._0) @@ -47,9 +53,19 @@ trait WitnessWith[TC[_]] extends Witness { val instance: TC[T] } -object WitnessWith extends WitnessWithInstances { +object WitnessWith { type Aux[TC[_], T0] = WitnessWith[TC] { type T = T0 } type Lt[TC[_], Lub] = WitnessWith[TC] { type T <: Lub } + + implicit def apply[TC[_], T](t: T)(implicit tc: TC[t.type]): WitnessWith.Aux[TC, t.type] { val instance: tc.type } = + instance[TC, t.type](t, tc) + + def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = + new WitnessWith[TC] { + type T = A + val value: T = v + val instance: tc.type = tc + } } trait NatWith[TC[_ <: Nat]] { diff --git a/core/src/main/scala/shapeless/syntax/singletons.scala b/core/src/main/scala/shapeless/syntax/singletons.scala index 015a29529..b3743bc53 100644 --- a/core/src/main/scala/shapeless/syntax/singletons.scala +++ b/core/src/main/scala/shapeless/syntax/singletons.scala @@ -47,3 +47,8 @@ object SingletonOps { val witness = w } } + +object singleton { + implicit def mkSingletonOps[T](t: T): SingletonOps.Aux[t.type] = + SingletonOps.instance[t.type](Witness(t)) +} diff --git a/core/src/main/scala_2.13+/shapeless/syntax/singleton.scala b/core/src/main/scala_2.13+/shapeless/syntax/singleton.scala deleted file mode 100644 index 83c8b5af3..000000000 --- a/core/src/main/scala_2.13+/shapeless/syntax/singleton.scala +++ /dev/null @@ -1,8 +0,0 @@ -package shapeless.syntax - -import shapeless.Witness - -object singleton { - implicit def mkSingletonOps[T](t: T): SingletonOps.Aux[t.type] = - SingletonOps.instance[t.type](Witness(t)) -} diff --git a/core/src/main/scala_2.13-/shapeless/LazyMacros.scala b/core/src/main/scala_2.13-/shapeless/LazyMacros.scala deleted file mode 100644 index aa23abcc8..000000000 --- a/core/src/main/scala_2.13-/shapeless/LazyMacros.scala +++ /dev/null @@ -1,370 +0,0 @@ -package shapeless - -import scala.collection.immutable.ListMap -import scala.reflect.macros.whitebox - -trait OpenImplicitMacros { - val c: whitebox.Context - - import c.universe._ - - def openImplicitTpe: Option[Type] = - c.openImplicits.headOption.map(_.pt) - - def openImplicitTpeParam: Option[Type] = - openImplicitTpe.map { - case TypeRef(_, _, List(tpe)) => - tpe.dealias - case other => - c.abort(c.enclosingPosition, s"Bad materialization: $other") - } - - def secondOpenImplicitTpe: Option[Type] = - c.openImplicits match { - case (List(_, second, _ @ _*)) => - Some(second.pt) - case _ => None - } -} - -class LazyMacros(val c: whitebox.Context) extends CaseClassMacros with OpenImplicitMacros { - import c.universe._ - import c.internal._ - import decorators._ - - def mkLazyImpl[I](implicit iTag: WeakTypeTag[I]): Tree = - mkImpl[I]( - (tree, actualType) => q"_root_.shapeless.Lazy.apply[$actualType]($tree)", - q"null.asInstanceOf[_root_.shapeless.Lazy[_root_.scala.Nothing]]" - ) - - def mkStrictImpl[I](implicit iTag: WeakTypeTag[I]): Tree = - mkImpl[I]( - (tree, actualType) => q"_root_.shapeless.Strict.apply[$actualType]($tree)", - q"null.asInstanceOf[_root_.shapeless.Strict[_root_.scala.Nothing]]" - ) - - def mkImpl[I](mkInst: (Tree, Type) => Tree, nullInst: => Tree)(implicit iTag: WeakTypeTag[I]): Tree = { - openImplicitTpeParam match { - case Some(tpe) => LazyMacros.deriveInstance(this)(tpe, mkInst) - case None => - val tpe = iTag.tpe.dealias - if (tpe.typeSymbol.isParameter) - nullInst - else - LazyMacros.deriveInstance(this)(tpe, mkInst) - } - } - - def setAnnotation(msg: String): Unit = { - val tree0 = - c.typecheck( - q""" - new _root_.scala.annotation.implicitNotFound("dummy") - """, - silent = false - ) - - class SubstMessage extends Transformer { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - - override def transform(tree: Tree): Tree = { - super.transform { - tree match { - case Literal(Constant("dummy")) => Literal(Constant(msg)) - case t => t - } - } - } - } - - val tree = new SubstMessage().transform(tree0) - - symbolOf[Lazy[Any]].setAnnotations(Annotation(tree)) - } - - def resetAnnotation: Unit = - setAnnotation("could not find Lazy implicit value of type ${T}") - - trait LazyDefinitions { - case class Instance( - instTpe: Type, - name: TermName, - symbol: Symbol, - inst: Option[Tree], - actualTpe: Type, - dependsOn: List[Type] - ) { - def ident = Ident(symbol) - } - - object Instance { - def apply(instTpe: Type) = { - val nme = TermName(c.freshName("inst")) - val sym = c.internal.setInfo(c.internal.newTermSymbol(NoSymbol, nme), instTpe) - - new Instance(instTpe, nme, sym, None, instTpe, Nil) - } - } - - class TypeWrapper(val tpe: Type) { - override def equals(other: Any): Boolean = - other match { - case TypeWrapper(tpe0) => tpe =:= tpe0 - case _ => false - } - override def toString = tpe.toString - } - - object TypeWrapper { - def apply(tpe: Type) = new TypeWrapper(tpe) - def unapply(tw: TypeWrapper): Option[Type] = Some(tw.tpe) - } - } - - class DerivationContext extends LazyDefinitions { - object State { - val empty = State("", ListMap.empty, Nil, Nil) - - private var current = Option.empty[State] - - def resolveInstance(state: State)(tpe: Type): Option[(State, Tree)] = { - val former = State.current - State.current = Some(state) - val (state0, tree) = - try { - val tree = c.inferImplicitValue(tpe, silent = true) - if(tree.isEmpty) { - tpe.typeSymbol.annotations. - find(_.tree.tpe =:= typeOf[_root_.scala.annotation.implicitNotFound]).foreach { _ => - setAnnotation(implicitNotFoundMessage(c)(tpe)) - } - } - (State.current.get, tree) - } finally { - State.current = former - } - - if (tree == EmptyTree) None - else Some((state0, tree)) - } - - def deriveInstance(instTpe0: Type, root: Boolean, mkInst: (Tree, Type) => Tree): Tree = { - if (root) { - assert(current.isEmpty) - val open = c.openImplicits - val name = if (open.length > 1) open(1).sym.name.toTermName.toString else "lazy" - current = Some(empty.copy(name = "anon$"+name)) - } - - derive(current.get)(instTpe0) match { - case Right((state, inst)) => - val (tree, actualType) = if (root) mkInstances(state)(instTpe0) else (inst.ident, inst.actualTpe) - current = if (root) None else Some(state) - mkInst(tree, actualType) - case Left(err) => - abort(err) - } - } - } - - case class State( - name: String, - dict: ListMap[TypeWrapper, Instance], - open: List[Instance], - /** Types whose derivation must fail no matter what */ - prevent: List[TypeWrapper] - ) { - def addDependency(tpe: Type): State = { - import scala.:: - val open0 = open match { - case Nil => Nil - case h :: t => h.copy(dependsOn = if (h.instTpe =:= tpe || h.dependsOn.exists(_ =:= tpe)) h.dependsOn else tpe :: h.dependsOn) :: t - } - copy(open = open0) - } - - private def update(inst: Instance): State = - copy(dict = dict.updated(TypeWrapper(inst.instTpe), inst)) - - def openInst(tpe: Type): (State, Instance) = { - val inst = Instance(tpe) - val state0 = addDependency(tpe) - (state0.copy(open = inst :: state0.open).update(inst), inst) - } - - def closeInst(tpe: Type, tree: Tree, actualTpe: Type): (State, Instance) = { - assert(open.nonEmpty) - assert(open.head.instTpe =:= tpe) - val instance = open.head - val sym = c.internal.setInfo(instance.symbol, actualTpe) - val instance0 = instance.copy(inst = Some(tree), actualTpe = actualTpe, symbol = sym) - (copy(open = open.tail).update(instance0), instance0) - } - - def lookup(instTpe: Type): Either[State, (State, Instance)] = - dict.get(TypeWrapper(instTpe)) match { - case Some(i) => Right((addDependency(instTpe), i)) - case None => Left(openInst(instTpe)._1) - } - - - def dependsOn(tpe: Type): List[Instance] = { - import scala.:: - def helper(tpes: List[List[Type]], acc: List[Instance]): List[Instance] = - tpes match { - case Nil => acc - case Nil :: t => - helper(t, acc) - case (h :: t0) :: t => - if (acc.exists(_.instTpe =:= h)) - helper(t0 :: t, acc) - else { - val inst = dict(TypeWrapper(h)) - helper(inst.dependsOn :: t0 :: t, inst :: acc) - } - } - - helper(List(List(tpe)), Nil) - } - } - - def stripRefinements(tpe: Type): Option[Type] = - tpe match { - case RefinedType(parents, decls) => Some(parents.head) - case _ => None - } - - def resolve(state: State)(inst: Instance): Option[(State, Instance)] = - resolve0(state)(inst.instTpe) - .filter{case (_, tree, _) => !tree.equalsStructure(inst.ident) } - .map {case (state0, extInst, actualTpe) => - state0.closeInst(inst.instTpe, extInst, actualTpe) - } - - def resolve0(state: State)(tpe: Type): Option[(State, Tree, Type)] = { - val extInstOpt = - State.resolveInstance(state)(tpe) - .orElse( - stripRefinements(tpe).flatMap(State.resolveInstance(state)) - ) - - extInstOpt.map {case (state0, extInst) => - (state0, extInst, extInst.tpe.finalResultType) - } - } - - def derive(state: State)(tpe: Type): Either[String, (State, Instance)] = - state.lookup(tpe).swap.flatMap { state0 => - val inst = state0.dict(TypeWrapper(tpe)) - resolve(state0)(inst).toLeft(s"Unable to derive $tpe") - }.swap - - // Workaround for https://issues.scala-lang.org/browse/SI-5465 - class StripUnApplyNodes extends Transformer { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - import global.nme - - override def transform(tree: Tree): Tree = { - super.transform { - tree match { - case UnApply(Apply(Select(qual, nme.unapply | nme.unapplySeq), List(Ident(nme.SELECTOR_DUMMY))), args) => - Apply(transform(qual), transformTrees(args)) - case UnApply(Apply(TypeApply(Select(qual, nme.unapply | nme.unapplySeq), _), List(Ident(nme.SELECTOR_DUMMY))), args) => - Apply(transform(qual), transformTrees(args)) - case t => t - } - } - } - } - - def mkInstances(state: State)(primaryTpe: Type): (Tree, Type) = { - val instances = state.dict.values.toList - val (from, to) = instances.map { d => (d.symbol, NoSymbol) }.unzip - - def clean(inst: Tree) = { - val cleanInst = c.untypecheck(c.internal.substituteSymbols(inst, from, to)) - new StripUnApplyNodes().transform(cleanInst) - } - - if (instances.length == 1) { - val instance = instances.head - import instance._ - inst match { - case Some(inst) => - val cleanInst = clean(inst) - (q"$cleanInst.asInstanceOf[$actualTpe]", actualTpe) - case None => - abort(s"Uninitialized $instTpe lazy implicit") - } - } else { - val instTrees = - instances.map { instance => - import instance._ - inst match { - case Some(inst) => - val cleanInst = clean(inst) - q"""lazy val $name: $actualTpe = $cleanInst.asInstanceOf[$actualTpe]""" - case None => - abort(s"Uninitialized $instTpe lazy implicit") - } - } - - val primaryInstance = (state.lookup(primaryTpe): @unchecked) match { - case Right((_, pi)) => pi - } - val primaryNme = primaryInstance.name - val clsName = TypeName(c.freshName(state.name)) - - val tree = - q""" - final class $clsName extends _root_.scala.Serializable { - ..$instTrees - } - (new $clsName).$primaryNme - """ - val actualType = primaryInstance.actualTpe - - (tree, actualType) - } - } - } -} - -object LazyMacros { - def dcRef(lm: LazyMacros): Option[LazyMacros#DerivationContext] = { - // N.B. openMacros/enclosingMacros annoyingly include macros which are not enclosing this macro at all, - // but simply happen to be expanding further up on the same compiler stack (and the compiler stack doesn't - // necessarily correspond to a single path through the AST - it can jump to other trees during typing), so - // we need to stop once the position of the open macros no longer matches ours - lm.c.openMacros.takeWhile(_.enclosingPosition == lm.c.enclosingPosition) - // use the first enclosing DerivationContext we find (if any) - .find(c => c.internal.attachments(c.macroApplication).contains[lm.DerivationContext]) - .flatMap(c => c.internal.attachments(c.macroApplication).get[lm.DerivationContext]) - } - - def deriveInstance(lm: LazyMacros)(tpe: lm.c.Type, mkInst: (lm.c.Tree, lm.c.Type) => lm.c.Tree): lm.c.Tree = { - val (dc, root) = - dcRef(lm) match { - case None => - lm.resetAnnotation - val dc = new lm.DerivationContext - lm.c.internal.updateAttachment(lm.c.macroApplication, dc) - (dc, true) - case Some(dc) => - (dc.asInstanceOf[lm.DerivationContext], false) - } - - if (root) - // Sometimes corrupted, and slows things too - lm.c.universe.asInstanceOf[scala.tools.nsc.Global].analyzer.resetImplicits() - - try { - dc.State.deriveInstance(tpe, root, mkInst) - } finally { - if(root) { - lm.c.internal.removeAttachment[lm.DerivationContext](lm.c.macroApplication) - } - } - } -} diff --git a/core/src/main/scala_2.13-/shapeless/syntax/singleton.scala b/core/src/main/scala_2.13-/shapeless/syntax/singleton.scala deleted file mode 100644 index 6590ab3a6..000000000 --- a/core/src/main/scala_2.13-/shapeless/syntax/singleton.scala +++ /dev/null @@ -1,10 +0,0 @@ -package shapeless.syntax - -import shapeless.SingletonTypeMacros - -import scala.language.experimental.macros - -object singleton { - implicit def mkSingletonOps(t: Any): SingletonOps = - macro SingletonTypeMacros.mkSingletonOps -} diff --git a/core/src/main/scala_2.13-/shapeless/versionspecifics.scala b/core/src/main/scala_2.13-/shapeless/versionspecifics.scala deleted file mode 100644 index fb38fa0fc..000000000 --- a/core/src/main/scala_2.13-/shapeless/versionspecifics.scala +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2018 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.collection.{GenTraversableLike, GenTraversableOnce} -import scala.collection.generic.{CanBuildFrom, IsTraversableLike} -import scala.collection.mutable.Builder -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - -trait LazyInstances { - implicit def mkLazy[I]: Lazy[I] = macro LazyMacros.mkLazyImpl[I] -} - -trait StrictInstances { - implicit def mkStrict[I]: Strict[I] = macro LazyMacros.mkStrictImpl[I] -} - -trait WitnessInstances { - implicit def of[T]: Witness.Aux[T] = - macro SingletonTypeMacros.materializeImpl[T] - - implicit def apply[T](t: T): Witness.Lt[T] = - macro SingletonTypeMacros.convertImpl -} - -trait WitnessWithInstances extends WitnessWithLowPriority { - implicit def apply[TC[_], T](t: T): WitnessWith.Lt[TC, T] = - macro SingletonTypeMacros.convertInstanceImpl1[TC] -} - -trait WitnessWithLowPriority { - implicit def apply2[H, TC2[_ <: H, _], S <: H, T](t: T): WitnessWith.Lt[({ type λ[x] = TC2[S, x] })#λ, T] = - macro SingletonTypeMacros.convertInstanceImpl2[H, TC2, S] - - def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] = - new WitnessWith[TC] { - type T = A - val value: T = v - val instance: TC[T] = tc - } - - def depInstance[TC[_] <: AnyRef, A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = - new WitnessWith[TC] { - type T = A - val value: T = v - val instance: tc.type = tc - } -} - -trait ScalaVersionSpecifics extends LP0 { - private[shapeless] type BuildFrom[-F, -E, +T] = CanBuildFrom[F, E, T] - private[shapeless] type Factory[-E, +T] = CanBuildFrom[Nothing, E, T] - private[shapeless] type IsRegularIterable[Repr] = IsTraversableLike[Repr] - private[shapeless] type LazyList[+T] = Stream[T] - private[shapeless] type IterableOnce[+T] = GenTraversableOnce[T] - private[shapeless] type IterableOps[T, CC[_], R] = GenTraversableLike[T, R] - - private[shapeless] def implicitNotFoundMessage(c: whitebox.Context)(tpe: c.Type): String = { - val global = c.universe.asInstanceOf[scala.tools.nsc.Global] - val gTpe = tpe.asInstanceOf[global.Type] - gTpe.typeSymbolDirect match { - case global.analyzer.ImplicitNotFoundMsg(msg) => - msg.format(global.newTermName("evidence"), gTpe) - case _ => - s"Implicit value of type $tpe not found" - } - } - - private[shapeless] implicit class GenTraversableLikeOps[T, Repr](gtl: GenTraversableLike[T, Repr]) { - def iterator: Iterator[T] = gtl.toIterator - } - - private[shapeless] implicit def canBuildFrom[F, E, T](cbf: CanBuildFrom[F, E, T]): CanBuildFromOps[F, E, T] = - new CanBuildFromOps[F, E, T](cbf) - - private[shapeless] implicit class NewEither[A, B](e: Either[A, B]) { - def flatMap[A1 >: A, B1](f: B => Either[A1, B1]): Either[A1, B1] = e match { - case Right(b) => f(b) - case _ => e.asInstanceOf[Either[A1, B1]] - } - - def toOption: Option[B] = e match { - case Right(b) => Some(b) - case _ => None - } - } - - private[shapeless] implicit class NewLeft[A, B](l: Left[A, B]) { - def value: A = l match { - case Left(a) => a - } - } - - private[shapeless] implicit class NewRight[A, B](r: Right[A, B]) { - def value: B = r match { - case Right(b) => b - } - } - - private[shapeless] implicit class NewIsIterable0[A0, Repr](itl: IsRegularIterable[Repr] { type A = A0 }) { - def apply(r: Repr): GenTraversableLike[A0, Repr] = itl.conversion(r) - } - - def cachedImplicit[T]: T = macro CachedImplicitMacros.cachedImplicitImpl[T] -} - -trait LP0 extends LP1 { - private[shapeless] implicit def canBuildFromNothing[E, T](cbf: CanBuildFrom[Nothing, E, T]): CanBuildFromOps[Nothing, E, T] = - new CanBuildFromOps[Nothing, E, T](cbf) - - private[shapeless] implicit class NewIsIterable1[Repr](val itl: IsRegularIterable[Repr]) { - def apply(r: Repr): GenTraversableLike[_, Repr] = itl.conversion(r) - } -} - -trait LP1 { - private[shapeless] implicit def canBuildEmptyFromNothing[T](cbf: CanBuildFrom[Nothing, Nothing, T]): CanBuildFromOps[Nothing, Nothing, T] = - new CanBuildFromOps[Nothing, Nothing, T](cbf) - - private[shapeless] class CanBuildFromOps[F, E, T](cbf: CanBuildFrom[F, E, T]) { - def newBuilder: Builder[E, T] = cbf() - def newBuilder(f: F): Builder[E, T] = cbf(f) - def fromSpecific(gto: GenTraversableOnce[E]): T = { - val b = cbf() - b ++= gto.toIterator - b.result() - } - } -} - -trait CaseClassMacrosVersionSpecifics { self: CaseClassMacros => - import c.universe._ - - val varargTpt = tq"_root_.scala.collection.Seq" - val varargTC = typeOf[scala.collection.Seq[_]].typeConstructor -} diff --git a/plugin/src/main/resources/scalac-plugin.xml b/plugin/src/main/resources/scalac-plugin.xml deleted file mode 100644 index bcc929137..000000000 --- a/plugin/src/main/resources/scalac-plugin.xml +++ /dev/null @@ -1,4 +0,0 @@ - - shapeless-plugin - shapeless.ShapelessPlugin - diff --git a/plugin/src/main/scala_2.13+/shapeless/ShapelessPlugin.scala b/plugin/src/main/scala_2.13+/shapeless/ShapelessPlugin.scala deleted file mode 100644 index a7a1c641c..000000000 --- a/plugin/src/main/scala_2.13+/shapeless/ShapelessPlugin.scala +++ /dev/null @@ -1,86 +0,0 @@ -package shapeless - -import scala.tools.nsc.Global -import scala.tools.nsc.plugins._ -import scala.tools.nsc.transform._ - -class ShapelessPlugin(val global: Global) extends Plugin { self => - import global._ - - val name = "shapeless-plugin" - val description = "Replaces shapeless.Lazy and shapeless.Strict with by-name implicits on Scala 2.13" - val components: List[PluginComponent] = ShapelessComponent :: Nil - - private object ShapelessComponent extends PluginComponent with Transform { - override val global: self.global.type = self.global - override val runsAfter = "parser" :: Nil - override val runsBefore = "namer" :: Nil - override val phaseName = self.name - override def newTransformer(unit: CompilationUnit) = ShapelessTransformer - - object ShapelessTransformer extends Transformer { - private[this] val Shapeless = TermName("shapeless") - private[this] val Lazy = TypeName("Lazy") - private[this] val Strict = TypeName("Strict") - private[this] val Value = TermName("value") - private[this] var lazyParams: Set[Name] = Set.empty - private[this] var strictParams: Set[Name] = Set.empty - - private object ShapelessType { - def unapply(tree: RefTree): Option[TypeName] = tree match { - case Ident(name: TypeName) => Some(name) - case Select(Ident(Shapeless), name: TypeName) => Some(name) - case Select(Select(Ident(nme.ROOTPKG), Shapeless), name: TypeName) => Some(name) - case _ => None - } - } - - override def transform(tree: Tree): Tree = tree match { - // def name[..tparams](...params)(implicit ip, ..): tpt = rhs - case DefDef(mods, name, tparams, paramss :+ (implicits @ List(ip, _*)), tpt, rhs) if ip.mods.isImplicit => - val restoreLazyParams = lazyParams - val restoreStrictParams = strictParams - try { - val adaptedImplicits = implicits.mapConserve(adaptImplicit) - val adaptedTpt = transform(tpt) - val adaptedRhs = transform(rhs) - if (adaptedImplicits.eq(implicits) && adaptedTpt.eq(tpt) && adaptedRhs.eq(rhs)) tree - else treeCopy.DefDef(tree, mods, name, tparams, paramss :+ adaptedImplicits, adaptedTpt, adaptedRhs) - } finally { - lazyParams = restoreLazyParams - strictParams = restoreStrictParams - } - - // param.value.T where param is a by-name implicit - case Select(Select(param @ Ident(name), Value), tpe: TypeName) if lazyParams(name) => - val message = s"By-name implicit parameter $name is not a stable identifier. Refactor to use the Aux pattern." - reporter.error(tree.pos, message) - Select(param, tpe) - - // param.value - case Select(param @ Ident(name), Value) if lazyParams(name) || strictParams(name) => - param - - case _ => - super.transform(tree) - } - - private def adaptImplicit(param: ValDef): ValDef = param.tpt match { - // Lazy[T] - case AppliedTypeTree(ShapelessType(Lazy), targs @ List(_)) => - lazyParams += param.name - val mods = param.mods | Flag.BYNAMEPARAM - val tpt = AppliedTypeTree(gen.rootScalaDot(tpnme.BYNAME_PARAM_CLASS_NAME), targs) - treeCopy.ValDef(param, mods, param.name, tpt, param.rhs) - - // Strict[T] - case AppliedTypeTree(ShapelessType(Strict), List(targ)) => - strictParams += param.name - treeCopy.ValDef(param, param.mods, param.name, targ, param.rhs) - - case _ => - param - } - } - } -} diff --git a/plugin/src/main/scala_2.13-/shapeless/ShapelessPlugin.scala b/plugin/src/main/scala_2.13-/shapeless/ShapelessPlugin.scala deleted file mode 100644 index 2315bb3f1..000000000 --- a/plugin/src/main/scala_2.13-/shapeless/ShapelessPlugin.scala +++ /dev/null @@ -1,66 +0,0 @@ -package shapeless - -import scala.tools.nsc.Global -import scala.tools.nsc.plugins._ -import scala.tools.nsc.transform._ - -class ShapelessPlugin(val global: Global) extends Plugin { self => - import global._ - - val name = "shapeless-plugin" - val description = "Replaces by-name implicits with shapeless.Lazy on Scala 2.12" - val components: List[PluginComponent] = ShapelessComponent :: Nil - - private object ShapelessComponent extends PluginComponent with Transform { - override val global: self.global.type = self.global - override val runsAfter = "parser" :: Nil - override val runsBefore = "namer" :: Nil - override val phaseName = self.name - override def newTransformer(unit: CompilationUnit) = ShapelessTransformer - - object ShapelessTransformer extends Transformer { - private[this] val Shapeless = TermName("shapeless") - private[this] val Lazy = TypeName("Lazy") - private[this] val Value = TermName("value") - private[this] var byNameParams: Set[Name] = Set.empty - - override def transform(tree: Tree): Tree = tree match { - // def name[..tparams](...params)(implicit ip, ..): tpt = rhs - case DefDef(mods, name, tparams, paramss :+ (implicits @ List(ip, _*)), tpt, rhs) if ip.mods.isImplicit => - val restoreByNameParams = byNameParams - try { - val adaptedImplicits = implicits.mapConserve(adaptImplicit) - val adaptedTpt = transform(tpt) - val adaptedRhs = transform(rhs) - if (adaptedImplicits.eq(implicits) && adaptedTpt.eq(tpt) && adaptedRhs.eq(rhs)) tree - else treeCopy.DefDef(tree, mods, name, tparams, paramss :+ adaptedImplicits, adaptedTpt, adaptedRhs) - } finally { - byNameParams = restoreByNameParams - } - - // param.T where param is a by-name implicit - case Select(param @ Ident(name), tpe: TypeName) if byNameParams(name) => - Select(Select(param, Value), tpe) - - // param where param is a by-name implicit - case param @ Ident(name) if byNameParams(name) => - Select(param, Value) - - case _ => - super.transform(tree) - } - - private def adaptImplicit(param: ValDef): ValDef = param.tpt match { - // => T - case AppliedTypeTree(ref: RefTree, targs @ List(_)) if ref.name == tpnme.BYNAME_PARAM_CLASS_NAME => - byNameParams += param.name - val mods = param.mods &~ Flag.BYNAMEPARAM - val tpt = AppliedTypeTree(Select(gen.rootId(Shapeless), Lazy), targs) - treeCopy.ValDef(param, mods, param.name, tpt, param.rhs) - - case _ => - param - } - } - } -} From 0b4a91ab9f8bd68d06b9c09e0ff2ac1fd0dc07fb Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 22:14:01 +0200 Subject: [PATCH 03/32] Remove Lazy and Strict for the most part --- core/src/main/scala/shapeless/lazy.scala | 164 ------------------ .../src/main/scala/shapeless/ops/hlists.scala | 8 +- core/src/main/scala/shapeless/unwrapped.scala | 14 +- core/src/test/scala/shapeless/lazy.scala | 40 ++--- .../main/scala/shapeless/examples/delta.scala | 8 +- .../shapeless/examples/recursionschemes.scala | 24 +-- 6 files changed, 47 insertions(+), 211 deletions(-) delete mode 100644 core/src/main/scala/shapeless/lazy.scala diff --git a/core/src/main/scala/shapeless/lazy.scala b/core/src/main/scala/shapeless/lazy.scala deleted file mode 100644 index a29f10a2b..000000000 --- a/core/src/main/scala/shapeless/lazy.scala +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2013-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.annotation.implicitNotFound - -/** - * Wraps a lazily computed value. Also circumvents cycles during implicit search, or wrong implicit divergences - * as illustrated below, and holds the corresponding implicit value lazily. - * - * The following implicit search sometimes fails to compile, because of a wrongly reported implicit divergence, - * {{{ - * case class ListCC(list: List[CC]) - * case class CC(i: Int, s: String) - * - * trait TC[T] - * - * object TC { - * implicit def intTC: TC[Int] = ??? - * implicit def stringTC: TC[String] = ??? - * implicit def listTC[T](implicit underlying: TC[T]): TC[List[T]] = ??? - * - * implicit def genericTC[F, G](implicit - * gen: Generic.Aux[F, G], - * underlying: TC[G] - * ): TC[F] = ??? - * - * implicit def hnilTC: TC[HNil] = ??? - * - * implicit def hconsTC[H, T <: HList](implicit - * headTC: TC[H], - * tailTC: TC[T] - * ): TC[H :: T] = ??? - * } - * - * implicitly[TC[ListCC]] // fails with: diverging implicit expansion for type TC[ListCC] - * }}} - * - * This wrongly reported implicit divergence can be circumvented by wrapping some of the implicit values in - * `Lazy`, - * {{{ - * case class ListCC(list: List[CC]) - * case class CC(i: Int, s: String) - * - * trait TC[T] - * - * object TC { - * implicit def intTC: TC[Int] = ??? - * implicit def stringTC: TC[String] = ??? - * implicit def listTC[T](implicit underlying: TC[T]): TC[List[T]] = ??? - * - * implicit def genericTC[F, G](implicit - * gen: Generic.Aux[F, G], - * underlying: Lazy[TC[G]] // wrapped in Lazy - * ): TC[F] = ??? - * - * implicit def hnilTC: TC[HNil] = ??? - * - * implicit def hconsTC[H, T <: HList](implicit - * headTC: Lazy[TC[H]], // wrapped in Lazy - * tailTC: TC[T] - * ): TC[H :: T] = ??? - * } - * - * implicitly[TC[ListCC]] - * }}} - * - * When looking for an implicit `Lazy[TC[T]]`, the `Lazy.mkLazy` macro will itself trigger the implicit search - * for a `TC[T]`. If this search itself triggers searches for types wrapped in `Lazy`, these will be done - * only once, their result put in a `lazy val`, and a reference to this `lazy val` will be returned as the corresponding - * value. It will then wrap all the resulting values together, and return a reference to the first one. - * - * E.g. with the above example definitions, when looking up for an implicit `TC[ListCC]`, the returned tree roughly looks - * like - * {{{ - * TC.genericTC( - * Generic[ListCC], // actually, the tree returned by Generic.materialize, not written here for the sake of brevity - * Lazy { - * lazy val impl1: TC[List[CC] :: HNil] = TC.hconsTC( - * Lazy(impl2), - * TC.hnilTC - * ) - * lazy val impl2: TC[List[CC]] = TC.listTC(TC.genericTC( - * Generic[CC], // actually, the tree returned by Generic.materialize - * Lazy(impl1) // cycles to the initial TC[List[CC] :: HNil] - * )) - * - * impl1 - * } - * ) - * }}} - * - */ -@implicitNotFound("could not find Lazy implicit value of type ${T}") -trait Lazy[+T] extends Serializable with LazyScalaCompat[T] { - def map[U](f: T => U): Lazy[U] = Lazy { f(value) } - def flatMap[U](f: T => Lazy[U]): Lazy[U] = Lazy { f(value).value } -} - -object Lazy { - implicit def apply[T](t: => T): Lazy[T] = - new Lazy[T] { - lazy val value: T = t - } - - implicit def mkLazy[I](implicit i: => I): Lazy[I] = Lazy(i) - - def unapply[T](lt: Lazy[T]): Option[T] = Some(lt.value) - - @implicitNotFound("could not find Lazy implicit values for all of the types enumerated in ${T}") - class Values[T <: HList](val values: T) extends Serializable - object Values { - implicit val hnilValues: Values[HNil] = new Values(HNil) - implicit def hconsValues[H, T <: HList](implicit lh: => H, t: Values[T]): Values[H :: T] = - new Values(lh :: t.values) - } - - def values[T <: HList](implicit lv: => Values[T]): T = lv.values -} - -object lazily { - def apply[T](implicit lv: => T): T = lv -} - -/** - * Wraps an eagerly computed value. Prevents wrongly reported implicit divergence, like `Lazy` does, but, - * unlike it, does not circumvent implicit cycles. - * - * Creation of `Lazy` instances usually triggers the creation of an anonymous class, to compute the wrapped - * value (e.g. with the by-name argument of `Lazy.apply`). `Strict` avoids that, which can lead to less - * overhead during compilation. - */ -@implicitNotFound("could not find Strict implicit value of type ${T}") -trait Strict[+T] extends Serializable { - val value: T - - def map[U](f: T => U): Strict[U] = Strict { f(value) } - def flatMap[U](f: T => Strict[U]): Strict[U] = Strict { f(value).value } -} - -object Strict { - implicit def apply[T](t: T): Strict[T] = - new Strict[T] { - val value: T = t - } - - implicit def mkStrict[I](implicit i: I): Strict[I] = Strict(i) - - def unapply[T](lt: Strict[T]): Option[T] = Some(lt.value) -} diff --git a/core/src/main/scala/shapeless/ops/hlists.scala b/core/src/main/scala/shapeless/ops/hlists.scala index 31d68282c..e9a1167cf 100644 --- a/core/src/main/scala/shapeless/ops/hlists.scala +++ b/core/src/main/scala/shapeless/ops/hlists.scala @@ -429,10 +429,10 @@ object hlist { } implicit def hlistLeftFolder[H, T <: HList, In, HF, OutH, FtOut] - (implicit f : Case2.Aux[HF, In, H, OutH], ft : Strict[LeftFolder.Aux[T, OutH, HF, FtOut]]): Aux[H :: T, In, HF, FtOut] = + (implicit f : Case2.Aux[HF, In, H, OutH], ft : LeftFolder.Aux[T, OutH, HF, FtOut]): Aux[H :: T, In, HF, FtOut] = new LeftFolder[H :: T, In, HF] { type Out = FtOut - def apply(l : H :: T, in : In) : Out = ft.value(l.tail, f(in, l.head)) + def apply(l : H :: T, in : In) : Out = ft(l.tail, f(in, l.head)) } } @@ -455,10 +455,10 @@ object hlist { } implicit def hlistRightFolder[H, T <: HList, In, HF, OutT] - (implicit ft : Strict[RightFolder.Aux[T, In, HF, OutT]], f : Case2[HF, H, OutT]): Aux[H :: T, In, HF, f.Result] = + (implicit ft : RightFolder.Aux[T, In, HF, OutT], f : Case2[HF, H, OutT]): Aux[H :: T, In, HF, f.Result] = new RightFolder[H :: T, In, HF] { type Out = f.Result - def apply(l : H :: T, in : In): Out = f(l.head, ft.value(l.tail, in)) + def apply(l : H :: T, in : In): Out = f(l.head, ft(l.tail, in)) } } diff --git a/core/src/main/scala/shapeless/unwrapped.scala b/core/src/main/scala/shapeless/unwrapped.scala index 140a4c504..dc2e0efa8 100644 --- a/core/src/main/scala/shapeless/unwrapped.scala +++ b/core/src/main/scala/shapeless/unwrapped.scala @@ -34,11 +34,11 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { implicit def unwrapAnyVal[W <: AnyVal, Repr, UI, UF](implicit gen: Generic.Aux[W, Repr], avh: AnyValHelper.Aux[Repr, UI], - chain: Strict[Unwrapped.Aux[UI, UF]] + chain: Unwrapped.Aux[UI, UF] ): 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))) + def unwrap(w: W): U = chain.unwrap(avh.unwrap(gen.to(w))) + def wrap(u: U): W = gen.from(avh.wrap(chain.wrap(u))) } sealed trait AnyValHelper[Repr] extends Serializable { @@ -58,12 +58,12 @@ trait UnwrappedInstances extends LowPriorityUnwrappedInstances { } implicit def newtypeUnwrapped[UI, Ops, UF](implicit - chain: Strict[Unwrapped.Aux[UI, UF]] - ): Aux[Newtype[UI, Ops], UF] = chain.value.asInstanceOf[Unwrapped.Aux[Newtype[UI, Ops], UF]] + chain: Unwrapped.Aux[UI, UF] + ): Aux[Newtype[UI, Ops], UF] = chain.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]] - ): Aux[T[UI, TT], UF] = chain.value.asInstanceOf[Unwrapped.Aux[T[UI, TT], UF]] + chain: Unwrapped.Aux[UI, UF] + ): Aux[T[UI, TT], UF] = chain.asInstanceOf[Unwrapped.Aux[T[UI, TT], UF]] } diff --git a/core/src/test/scala/shapeless/lazy.scala b/core/src/test/scala/shapeless/lazy.scala index b71907735..bbeea3b74 100644 --- a/core/src/test/scala/shapeless/lazy.scala +++ b/core/src/test/scala/shapeless/lazy.scala @@ -39,9 +39,9 @@ class LazyStrictTests { i } - def summonStrictLong(implicit sl: Strict[Long]): Long = { + def summonStrictLong(implicit sl: Long): Long = { effects += 7 - val i = sl.value + val i = sl effects += 8 i } @@ -72,9 +72,9 @@ class LazyStrictTests { def effectfulStrictInt: Int = { effects += 6 ; 23 } - def useEffectfulStrictInt(li: Strict[Int]): Int = { + def useEffectfulStrictInt(li: Int): Int = { effects += 7 - val i = li.value + val i = li effects += 8 i } @@ -104,9 +104,9 @@ class LazyStrictTests { i } - def useEffectfulStrictInt(li: Strict[Int]): Int = { + def useEffectfulStrictInt(li: Int): Int = { effects += 7 - val i = li.value + val i = li effects += 8 i } @@ -126,16 +126,16 @@ class LazyStrictTests { def testInlineConversion: Unit = { val effects = ListBuffer[Int]() - def useEffectfulLazyInt(li: Lazy[Int]): Int = { + def useEffectfulLazyInt(li: => Int): Int = { effects += 3 - val i = li.value + val i = li effects += 4 i } - def useEffectfulStrictInt(si: Strict[Int]): Int = { + def useEffectfulStrictInt(si: Int): Int = { effects += 7 - val i = si.value + val i = si effects += 8 i } @@ -237,8 +237,8 @@ class LazyStrictTests { @Test def testEta: Unit = { - implicitly[Lazy[Bar[Int]]].value.foo _ - implicitly[Strict[Bar[Int]]].value.foo _ + //implicitly[=> Bar[Int]].value.foo _ + implicitly[Bar[Int]].foo _ () } @@ -247,8 +247,8 @@ class LazyStrictTests { } object Baz { - def lazyBaz[T, U](t: T)(implicit bt: Lazy[Aux[T, U]]): Aux[T, U] = bt.value - def strictBaz[T, U](t: T)(implicit bt: Strict[Aux[T, U]]): Aux[T, U] = bt.value + def lazyBaz[T, U](t: T)(implicit bt: => Aux[T, U]): Aux[T, U] = bt + def strictBaz[T, U](t: T)(implicit bt: Aux[T, U]): Aux[T, U] = bt type Aux[T, U0] = Baz[T] { type U = U0 } @@ -271,13 +271,13 @@ class LazyStrictTests { @Test def testExtractors: Unit = { - implicitly[Lazy[Generic[Symbol]]] - implicitly[Strict[Generic[Symbol]]] + //implicitly[=> Generic[Symbol]] + implicitly[Generic[Symbol]] val x = { case class Leaf[A](value: A) - implicitly[Lazy[Generic[Leaf[Int]]]] - implicitly[Strict[Generic[Leaf[Int]]]] + //implicitly[=> Generic[Leaf[Int]]] + implicitly[Generic[Leaf[Int]]] () } } @@ -321,7 +321,7 @@ class LazyStrictTests { ): Readable[M[String, T]] = new Readable implicitly[Readable[Id]] - implicitly[Lazy[Readable[Id]]] - implicitly[Strict[Readable[Id]]] + //implicitly[=> Readable[Id]] + implicitly[Readable[Id]] } } diff --git a/examples/src/main/scala/shapeless/examples/delta.scala b/examples/src/main/scala/shapeless/examples/delta.scala index 8c4c3dd38..50187b415 100644 --- a/examples/src/main/scala/shapeless/examples/delta.scala +++ b/examples/src/main/scala/shapeless/examples/delta.scala @@ -94,12 +94,12 @@ object Delta extends Delta0 { } implicit def deriveHCons[H, T <: HList, HO]( - implicit deltaH: => Delta.Aux[H, HO], deltaT: Strict[Delta[T] { type Out <: HList }] - ): Delta.Aux[H :: T, HO :: deltaT.value.Out] = new Delta[H :: T] { - type Out = HO :: deltaT.value.Out + implicit deltaH: => Delta.Aux[H, HO], deltaT: Delta[T] { type Out <: HList } + ): Delta.Aux[H :: T, HO :: deltaT.Out] = new Delta[H :: T] { + type Out = HO :: deltaT.Out def apply(before: H :: T, after: H :: T): Out = - deltaH(before.head, after.head) :: deltaT.value(before.tail, after.tail) + deltaH(before.head, after.head) :: deltaT(before.tail, after.tail) } } diff --git a/examples/src/main/scala/shapeless/examples/recursionschemes.scala b/examples/src/main/scala/shapeless/examples/recursionschemes.scala index 2ccc745af..1bc55f851 100644 --- a/examples/src/main/scala/shapeless/examples/recursionschemes.scala +++ b/examples/src/main/scala/shapeless/examples/recursionschemes.scala @@ -310,38 +310,38 @@ package recursionschemes { } implicit def hcons[U, H, T <: HList]( - implicit H: Strict[Rec[U, H]], T: RecHList[U, T] + implicit H: Rec[U, H], T: RecHList[U, T] ): RecHList[U, H :: T] { - type F[x] = H.value.F[x] :: T.F[x] + type F[x] = H.F[x] :: T.F[x] } = new RecHList[U, H :: T] { - type F[x] = H.value.F[x] :: T.F[x] - def tie(fu: F[U]): H :: T = H.value.tie(fu.head) :: T.tie(fu.tail) - def untie(l: H :: T): F[U] = H.value.untie(l.head) :: T.untie(l.tail) + type F[x] = H.F[x] :: T.F[x] + def tie(fu: F[U]): H :: T = H.tie(fu.head) :: T.tie(fu.tail) + def untie(l: H :: T): F[U] = H.untie(l.head) :: T.untie(l.tail) def traverse[G[_], A, B](fa: F[A])(f: A => G[B])(implicit G: Applicative[G]): G[F[B]] = - G.map2(H.value.traverse(fa.head)(f), T.traverse(fa.tail)(f))(_ :: _) + G.map2(H.traverse(fa.head)(f), T.traverse(fa.tail)(f))(_ :: _) } implicit def ccons[T, L, R <: Coproduct]( - implicit L: Strict[Rec[T, L]], R: RecCoproduct[T, R] + implicit L: Rec[T, L], R: RecCoproduct[T, R] ): RecCoproduct[T, L :+: R] { - type F[t] = L.value.F[t] :+: R.F[t] + type F[t] = L.F[t] :+: R.F[t] } = new RecCoproduct[T, L :+: R] { - type F[t] = L.value.F[t] :+: R.F[t] + type F[t] = L.F[t] :+: R.F[t] def tie(ft: F[T]): L :+: R = ft match { - case Inl(fl) => Inl(L.value.tie(fl)) + case Inl(fl) => Inl(L.tie(fl)) case Inr(fr) => Inr(R.tie(fr)) } def untie(c: L :+: R): F[T] = c match { - case Inl(l) => Inl(L.value.untie(l)) + case Inl(l) => Inl(L.untie(l)) case Inr(r) => Inr(R.untie(r)) } def traverse[G[_], A, B](fa: F[A])(f: A => G[B])( implicit G: Applicative[G] ): G[F[B]] = fa match { - case Inl(fl) => G.map(L.value.traverse(fl)(f))(Inl.apply) + case Inl(fl) => G.map(L.traverse(fl)(f))(Inl.apply) case Inr(fr) => G.map(R.traverse(fr)(f))(Inr.apply) } } From e5c89ac8632f58384db455dab4efd3bace4bfab4 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 22:43:45 +0200 Subject: [PATCH 04/32] Remove type providers and some other type parsing macros --- .../main/scala-2/shapeless/coproduct.scala | 38 ------------------- core/src/main/scala-2/shapeless/hlists.scala | 19 ---------- .../src/main/scala-2/shapeless/labelled.scala | 31 --------------- core/src/main/scala-2/shapeless/records.scala | 1 - .../main/scala-2/shapeless/singletons.scala | 13 ------- .../scala-2/shapeless/typeoperators.scala | 33 ---------------- core/src/main/scala-2/shapeless/unions.scala | 1 - .../main/scala-3/shapeless/coproduct.scala | 36 ------------------ core/src/main/scala-3/shapeless/hlists.scala | 19 ---------- core/src/main/scala-3/shapeless/records.scala | 1 - .../main/scala-3/shapeless/singletons.scala | 4 -- .../scala-3/shapeless/typeoperators.scala | 8 +--- core/src/main/scala-3/shapeless/unions.scala | 1 - core/src/main/scala/shapeless/coproduct.scala | 4 +- core/src/main/scala/shapeless/hlists.scala | 2 +- .../src/main/scala/shapeless/singletons.scala | 4 +- .../main/scala/shapeless/typeoperators.scala | 6 +-- 17 files changed, 5 insertions(+), 216 deletions(-) delete mode 100644 core/src/main/scala-2/shapeless/coproduct.scala delete mode 100644 core/src/main/scala-3/shapeless/coproduct.scala diff --git a/core/src/main/scala-2/shapeless/coproduct.scala b/core/src/main/scala-2/shapeless/coproduct.scala deleted file mode 100644 index ba321fcdf..000000000 --- a/core/src/main/scala-2/shapeless/coproduct.scala +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2013-14 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.language.experimental.macros - -trait CoproductScalaCompat { - - /** - * Allows to specify a `Coproduct` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = Coproduct.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = Coproduct.`'a, 'b, 'c`.T - * type TwoTrueStr = Coproduct.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.coproductType -} diff --git a/core/src/main/scala-2/shapeless/hlists.scala b/core/src/main/scala-2/shapeless/hlists.scala index 3d21a4caf..86aadb4b3 100644 --- a/core/src/main/scala-2/shapeless/hlists.scala +++ b/core/src/main/scala-2/shapeless/hlists.scala @@ -19,25 +19,6 @@ package shapeless import scala.language.experimental.macros import scala.reflect.macros.whitebox -trait HListScalaCompat { - - /** - * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = HList.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = HList.`'a, 'b, 'c`.T - * type TwoTrueStr = HList.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.hlistType -} - trait NatProductArgsScalaCompat { def applyDynamic(method: String)(args: Int*): Any = macro ProductMacros.forwardNatImpl } diff --git a/core/src/main/scala-2/shapeless/labelled.scala b/core/src/main/scala-2/shapeless/labelled.scala index ab8243a34..ea36d5304 100644 --- a/core/src/main/scala-2/shapeless/labelled.scala +++ b/core/src/main/scala-2/shapeless/labelled.scala @@ -55,9 +55,6 @@ class LabelledMacros(override val c: whitebox.Context) extends GenericMacros(c) private def parseTypeOrFail(tpe: String): Type = parseType(tpe).getOrElse(abort(s"Malformed literal or standard type $tpe")) - private def parseLiteralTypeOrFail(tpe: String): Type = - parseLiteralType(tpe).getOrElse(abort(s"Malformed literal type $tpe")) - private def labelsOf(tpe: Type): List[Constant] = if (isProduct(tpe)) fieldsOf(tpe).map { case (f, _) => nameAsValue(f) } else if (isCoproduct(tpe)) ctorsOf(tpe).map(c => nameAsValue(nameOf(c))) @@ -82,34 +79,6 @@ class LabelledMacros(override val c: whitebox.Context) extends GenericMacros(c) q"${reify(Labelling)}.instance[$tpe, $labelsType]($labelsValue.asInstanceOf[$labelsType])" } - def recordType(tpeSelector: Tree): Tree = - labelledType(tpeSelector, "record", hnilTpe, hconsTpe) - - def unionType(tpeSelector: Tree): Tree = - labelledType(tpeSelector, "union", cnilTpe, cconsTpe) - - def labelledType(tpeSelector: Tree, variety: String, nil: Type, cons: Type): Tree = { - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val labelledTpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => - element.split("->") match { - case Array(keyString, valueString) => - val key = parseLiteralTypeOrFail(keyString.trim) - val value = parseTypeOrFail(valueString.trim) - appliedType(cons, FieldType(key, value), acc) - case _ => - abort(s"Malformed $variety type $tpeString") - } - } - - typeCarrier(labelledTpe) - } - - def hlistType(tpeSelector: Tree): Tree = - nonLabelledType(tpeSelector, hnilTpe, hconsTpe) - - def coproductType(tpeSelector: Tree): Tree = - nonLabelledType(tpeSelector, cnilTpe, cconsTpe) - def nonLabelledType(tpeSelector: Tree, nil: Type, cons: Type): Tree = { val q"${tpeString: String}" = (tpeSelector: @unchecked) val tpe = commaSeparated(tpeString).foldRight(nil) { (element, acc) => diff --git a/core/src/main/scala-2/shapeless/records.scala b/core/src/main/scala-2/shapeless/records.scala index 21610fd86..1c89d6488 100644 --- a/core/src/main/scala-2/shapeless/records.scala +++ b/core/src/main/scala-2/shapeless/records.scala @@ -22,7 +22,6 @@ import scala.reflect.macros.whitebox trait RecordScalaCompat { def applyDynamic(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordEmptyImpl def applyDynamicNamed(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordNamedImpl - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.recordType } trait RecordArgsScalaCompat { diff --git a/core/src/main/scala-2/shapeless/singletons.scala b/core/src/main/scala-2/shapeless/singletons.scala index dd06fb459..0bc3d584b 100644 --- a/core/src/main/scala-2/shapeless/singletons.scala +++ b/core/src/main/scala-2/shapeless/singletons.scala @@ -21,11 +21,6 @@ import shapeless.syntax.SingletonOps import scala.language.experimental.macros import scala.reflect.macros.whitebox -trait WitnessScalaCompat { - def selectDynamic(tpeSelector: String): Any = - macro SingletonTypeMacros.witnessTypeImpl -} - trait NatWithScalaCompat { implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = @@ -233,14 +228,6 @@ class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils wi def mkSingletonOps(t: Tree): Tree = extractResult(t) { (tpe, tree) => mkOps(tpe, mkWitness(tpe, tree)) } - def witnessTypeImpl(tpeSelector: Tree): Tree = { - val q"${tpeString: String}" = (tpeSelector: @unchecked) - val tpe = parseLiteralType(tpeString) - .getOrElse(c.abort(c.enclosingPosition, s"Malformed literal $tpeString")) - - fieldTypeCarrier(tpe) - } - def materializeWiden[T: WeakTypeTag, Out: WeakTypeTag]: Tree = { val tpe = weakTypeOf[T].dealias val wideTpe = tpe.widen diff --git a/core/src/main/scala-2/shapeless/typeoperators.scala b/core/src/main/scala-2/shapeless/typeoperators.scala index a73e7db25..d681249db 100644 --- a/core/src/main/scala-2/shapeless/typeoperators.scala +++ b/core/src/main/scala-2/shapeless/typeoperators.scala @@ -6,8 +6,6 @@ import scala.util.{Failure, Success, Try} trait theScalaCompat { def apply[T](implicit t: T): T = macro TheMacros.applyImpl - - def selectDynamic(tpeSelector: String): Any = macro TheMacros.implicitlyImpl } class TheMacros(val c: whitebox.Context) { @@ -46,34 +44,3 @@ class TheMacros(val c: whitebox.Context) { } } } - -trait TypeOfScalaCompat { - def selectDynamic(code: String): Any = macro TypeOfMacros.selectDynamic -} - -private[shapeless] final class TypeOfMacros(val c: whitebox.Context) { - import c.universe.{Try => _, _} - import internal._, decorators._ - - def selectDynamic(code: Tree): Tree = { - - val q"${codeString: String}" = (code: @unchecked) - val tpe = c.parse(codeString) match { - case Typed(expr, tpt) => - val baseType = c.typecheck(tpt, mode = c.TYPEmode) - c.typecheck(expr, pt = baseType.tpe).tpe - case expr => - c.typecheck(expr).tpe - } - - // Bail for primitives because the resulting trees with type set to Unit - // will crash the compiler - val symbol = tpe.typeSymbol - if (symbol.isClass && symbol.asClass.isPrimitive) - c.abort(c.enclosingPosition, s"Primitive type $tpe may not be used in this context") - - // We can't yield a useful value here, so return Unit instead which is at least guaranteed - // to result in a runtime exception if the value is used in term position. - Literal(Constant(())).setType(tpe) - } -} diff --git a/core/src/main/scala-2/shapeless/unions.scala b/core/src/main/scala-2/shapeless/unions.scala index c3e444a8c..de2663ee6 100644 --- a/core/src/main/scala-2/shapeless/unions.scala +++ b/core/src/main/scala-2/shapeless/unions.scala @@ -21,7 +21,6 @@ import scala.reflect.macros.whitebox trait UnionScalaCompat { def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = macro UnionMacros.mkUnionNamedImpl[U] - def selectDynamic(tpeSelector: String): Any = macro LabelledMacros.unionType } class UnionMacros(val c: whitebox.Context) { diff --git a/core/src/main/scala-3/shapeless/coproduct.scala b/core/src/main/scala-3/shapeless/coproduct.scala deleted file mode 100644 index c5cd4ef3a..000000000 --- a/core/src/main/scala-3/shapeless/coproduct.scala +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2013-14 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -trait CoproductScalaCompat { - - /** - * Allows to specify a `Coproduct` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = Coproduct.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = Coproduct.`'a, 'b, 'c`.T - * type TwoTrueStr = Coproduct.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = ??? -} diff --git a/core/src/main/scala-3/shapeless/hlists.scala b/core/src/main/scala-3/shapeless/hlists.scala index dcdf0a60b..46d801d08 100644 --- a/core/src/main/scala-3/shapeless/hlists.scala +++ b/core/src/main/scala-3/shapeless/hlists.scala @@ -16,25 +16,6 @@ package shapeless -trait HListScalaCompat { - - /** - * Allows to specify an `HList` type with a syntax similar to `Record` and `Union`, as follows, - * - * {{{ - * type ISB = HList.`Int, String, Boolean`.T - * }}} - * - * Literal types are allowed, so that the following is valid, - * - * {{{ - * type ABC = HList.`'a, 'b, 'c`.T - * type TwoTrueStr = HList.`2, true, "str"`.T - * }}} - */ - def selectDynamic(tpeSelector: String): Any = ??? -} - trait NatProductArgsScalaCompat { def applyDynamic(method: String)(args: Int*): Any = ??? } diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala index 936a00a95..af6ded925 100644 --- a/core/src/main/scala-3/shapeless/records.scala +++ b/core/src/main/scala-3/shapeless/records.scala @@ -19,7 +19,6 @@ package shapeless trait RecordScalaCompat { def applyDynamic(method: String)(rec: Any*): HList = ??? def applyDynamicNamed(method: String)(rec: Any*): HList = ??? - def selectDynamic(tpeSelector: String): Any = ??? } trait RecordArgsScalaCompat { diff --git a/core/src/main/scala-3/shapeless/singletons.scala b/core/src/main/scala-3/shapeless/singletons.scala index dfd44a404..5fed8e034 100644 --- a/core/src/main/scala-3/shapeless/singletons.scala +++ b/core/src/main/scala-3/shapeless/singletons.scala @@ -16,10 +16,6 @@ package shapeless -trait WitnessScalaCompat { - def selectDynamic(tpeSelector: String): Any = ??? -} - trait NatWithScalaCompat { implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = ??? diff --git a/core/src/main/scala-3/shapeless/typeoperators.scala b/core/src/main/scala-3/shapeless/typeoperators.scala index ea44a6b3c..42a8d5d3b 100644 --- a/core/src/main/scala-3/shapeless/typeoperators.scala +++ b/core/src/main/scala-3/shapeless/typeoperators.scala @@ -1,11 +1,5 @@ package shapeless trait theScalaCompat { - def apply[T](implicit t: T): T = ??? - - def selectDynamic(tpeSelector: String): Any = ??? -} - -trait TypeOfScalaCompat { - def selectDynamic(code: String): Any = ??? + transparent inline def summon[T](using inline x: T): x.type = x } diff --git a/core/src/main/scala-3/shapeless/unions.scala b/core/src/main/scala-3/shapeless/unions.scala index df6398de8..bde40385d 100644 --- a/core/src/main/scala-3/shapeless/unions.scala +++ b/core/src/main/scala-3/shapeless/unions.scala @@ -18,5 +18,4 @@ package shapeless trait UnionScalaCompat { def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = ??? - def selectDynamic(tpeSelector: String): Any = ??? } diff --git a/core/src/main/scala/shapeless/coproduct.scala b/core/src/main/scala/shapeless/coproduct.scala index 8f186213e..8f847cc9c 100644 --- a/core/src/main/scala/shapeless/coproduct.scala +++ b/core/src/main/scala/shapeless/coproduct.scala @@ -16,8 +16,6 @@ package shapeless -import scala.language.dynamics - import scala.annotation.tailrec /** Encodes a coproduct type, such as a sealed family of case classes. @@ -118,7 +116,7 @@ sealed trait CNil extends Coproduct { def impossible: Nothing } -object Coproduct extends Dynamic with CoproductScalaCompat { +object Coproduct { import ops.coproduct.Inject import ops.coproduct.RuntimeInject import syntax.CoproductOps diff --git a/core/src/main/scala/shapeless/hlists.scala b/core/src/main/scala/shapeless/hlists.scala index d223f5dc4..fd1949c6d 100644 --- a/core/src/main/scala/shapeless/hlists.scala +++ b/core/src/main/scala/shapeless/hlists.scala @@ -56,7 +56,7 @@ sealed trait HNil extends HList { */ case object HNil extends HNil -object HList extends Dynamic with HListScalaCompat { +object HList { import ops.hlist._ import syntax.HListOps diff --git a/core/src/main/scala/shapeless/singletons.scala b/core/src/main/scala/shapeless/singletons.scala index 60f6def28..d3d0a2324 100644 --- a/core/src/main/scala/shapeless/singletons.scala +++ b/core/src/main/scala/shapeless/singletons.scala @@ -16,8 +16,6 @@ package shapeless -import scala.language.dynamics - /** Provides the value corresponding to a singleton type. * * See SIP-23 for a related proposed language change. @@ -27,7 +25,7 @@ trait Witness extends Serializable { val value: T {} } -object Witness extends Dynamic with WitnessScalaCompat { +object Witness { type Aux[T0] = Witness { type T = T0 } type Lt[Lub] = Witness { type T <: Lub } diff --git a/core/src/main/scala/shapeless/typeoperators.scala b/core/src/main/scala/shapeless/typeoperators.scala index 018509b43..c2a239951 100644 --- a/core/src/main/scala/shapeless/typeoperators.scala +++ b/core/src/main/scala/shapeless/typeoperators.scala @@ -16,8 +16,6 @@ package shapeless -import scala.language.dynamics - object tag { def apply[U] = Tagger.asInstanceOf[Tagger[U]] @@ -102,9 +100,7 @@ object newtype { * i: Int = 23 * }}} */ -object the extends Dynamic with theScalaCompat - -object TypeOf extends Dynamic with TypeOfScalaCompat +object the extends theScalaCompat /** * Type class witnessing the least upper bound of a pair of types and providing conversions from each to their common From f3298d61de17ab91e70c33d4782ffdc8a123b98a Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 22:52:58 +0200 Subject: [PATCH 05/32] Remove method forwarder macros (RecordArgs and co) --- core/src/main/scala-2/shapeless/hlists.scala | 142 ------------------ core/src/main/scala-2/shapeless/records.scala | 49 ------ core/src/main/scala-3/shapeless/hlists.scala | 33 ---- core/src/main/scala-3/shapeless/records.scala | 9 -- core/src/main/scala/shapeless/alacarte.scala | 5 +- core/src/main/scala/shapeless/hlists.scala | 90 ----------- core/src/main/scala/shapeless/records.scala | 43 ------ .../main/scala/shapeless/syntax/hlists.scala | 10 -- 8 files changed, 4 insertions(+), 377 deletions(-) delete mode 100644 core/src/main/scala-2/shapeless/hlists.scala delete mode 100644 core/src/main/scala-3/shapeless/hlists.scala diff --git a/core/src/main/scala-2/shapeless/hlists.scala b/core/src/main/scala-2/shapeless/hlists.scala deleted file mode 100644 index 86aadb4b3..000000000 --- a/core/src/main/scala-2/shapeless/hlists.scala +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2011-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.language.experimental.macros -import scala.reflect.macros.whitebox - -trait NatProductArgsScalaCompat { - def applyDynamic(method: String)(args: Int*): Any = macro ProductMacros.forwardNatImpl -} - -trait ProductArgsScalaCompat { - def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardImpl -} - -trait FromProductArgsScalaCompat { - def applyDynamic(method: String)(hlist: HList): Any = macro ProductMacros.forwardFromProductImpl -} - -trait SingletonProductArgsScalaCompat { - def applyDynamic(method: String)(args: Any*): Any = macro ProductMacros.forwardSingletonImpl -} - -class ProductMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { - import c.universe._ - - def forwardImpl(method: Tree)(args: Tree*): Tree = forward(method, args, false) - - def forwardNatImpl(method: Tree)(args: Tree*): Tree = forwardNat(method, args) - - def forwardSingletonImpl(method: Tree)(args: Tree*): Tree = forward(method, args, true) - - def forwardNat(method: Tree, args: Seq[Tree]): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString+"NatProduct") - - if(lhsTpe.member(methodName) == NoSymbol) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val meth = lhsTpe.member(methodName).asMethod - - if (!meth.paramLists.isEmpty && (meth.paramLists(0) forall (_.isImplicit))) { - val typeParamsTree = mkProductNatTypeParamsImpl(args) - q""" $lhs.$methodName[${typeParamsTree}] """ - } else { - val argsTree = mkProductNatImpl(args) - q""" $lhs.$methodName($argsTree) """ - } - } - - def forward(method: Tree, args: Seq[Tree], narrow: Boolean): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString+"Product") - - if(lhsTpe.member(methodName) == NoSymbol) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val argsTree = mkProductImpl(args, narrow) - - q""" $lhs.$methodName($argsTree) """ - } - - def forwardFromProductImpl(method: Tree)(hlist: Tree): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - - val q"${methodString: String}" = (method: @unchecked) - - if (!methodString.matches(".*Product$")) - c.abort(c.enclosingPosition, s"missing method '$methodString'") - - val methodName = TermName(methodString.replaceAll("Product$", "")) - - if(!lhsTpe.member(methodName).isMethod) - c.abort(c.enclosingPosition, s"missing method '$methodName'") - - val methodSym = lhsTpe.member(methodName).asMethod - val paramss = methodSym.paramLists.filterNot(_.forall(_.isImplicit)) - val argss = paramss.map(_.map(_ => TermName(c.freshName("pat")))) - val names = argss.flatten - - val pattern = - names.foldRight(q"_root_.shapeless.HNil": Tree) { - case (nme, acc) => pq"_root_.shapeless.::($nme, $acc)" - } - - q""" - $hlist match { - case $pattern => $lhs.$methodName(...$argss) - } - """ - } - - def mkProductImpl(args: Seq[Tree], narrow: Boolean): Tree = { - args.foldRight((hnilTpe, q"_root_.shapeless.HNil: $hnilTpe": Tree)) { - case(elem, (accTpe, accTree)) => - val (neTpe, neTree) = if(narrow) narrowValue(elem) else (elem.tpe, elem) - (appliedType(hconsTpe, List(neTpe, accTpe)), q"""_root_.shapeless.::[$neTpe, $accTpe]($neTree, $accTree)""") - }._2 - } - - def mkProductNatImpl(args: Seq[Tree]): Tree = { - args.foldRight((tq"_root_.shapeless.HNil", q"_root_.shapeless.HNil: $hnilTpe"): (Tree, Tree)) { - case(NatLiteral(n), (accTpt, accTree)) => - val neTpt = mkNatTpt(n) - val neTree = mkNatValue(n) - (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", q"""_root_.shapeless.::[$neTpt, $accTpt]($neTree, $accTree)""") - case (elem, _) => - c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") - }._2 - } - - def mkProductNatTypeParamsImpl(args: Seq[Tree]): Tree = { - args.foldRight((tq"_root_.shapeless.HNil", tq"_root_.shapeless.HNil"): (Tree, Tree)) { - case (NatLiteral(n), (accTpt, _)) => - val neTpt = mkNatTpt(n) - (tq"""_root_.shapeless.::[$neTpt, $accTpt]""", tq"""_root_.shapeless.::[$neTpt, $accTpt]""") - case (elem, _) => - c.abort(c.enclosingPosition, s"Expression $elem does not evaluate to a non-negative Int literal") - }._2 - } -} diff --git a/core/src/main/scala-2/shapeless/records.scala b/core/src/main/scala-2/shapeless/records.scala index 1c89d6488..58e638758 100644 --- a/core/src/main/scala-2/shapeless/records.scala +++ b/core/src/main/scala-2/shapeless/records.scala @@ -24,15 +24,6 @@ trait RecordScalaCompat { def applyDynamicNamed(method: String)(rec: Any*): HList = macro RecordMacros.mkRecordNamedImpl } -trait RecordArgsScalaCompat { - def applyDynamic(method: String)(): Any = macro RecordMacros.forwardImpl - def applyDynamicNamed(method: String)(rec: Any*): Any = macro RecordMacros.forwardNamedImpl -} - -trait FromRecordArgsScalaCompat { - def applyDynamic[L <: HList](method: String)(rec: L): Any = macro RecordMacros.forwardFromRecordImpl[L] -} - class RecordMacros(val c: whitebox.Context) extends CaseClassMacros { import c.universe._ import internal.constantType @@ -51,36 +42,6 @@ class RecordMacros(val c: whitebox.Context) extends CaseClassMacros { mkRecordImpl(rec: _*) } - def forwardImpl(method: Tree)(): Tree = - forwardNamedImpl(method)() - - def forwardNamedImpl(method: Tree)(rec: Tree*): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - val q"${methodString: String}" = (method: @unchecked) - val methodName = TermName(methodString + "Record") - if (lhsTpe.member(methodName) == NoSymbol) - abort(s"missing method '$methodName'") - - val recTree = mkRecordImpl(rec: _*) - q"$lhs.$methodName($recTree)" - } - - def forwardFromRecordImpl[L <: HList](method: Tree)(rec: Expr[L]): Tree = { - val lhs = c.prefix.tree - val lhsTpe = lhs.tpe - val q"${methodString: String}" = (method: @unchecked) - if (!methodString.matches(".*Record$")) - abort(s"missing method '$methodString'") - - val methodName = TermName(methodString.replaceAll("Record$", "")) - if (!lhsTpe.member(methodName).isMethod) - abort(s"missing method '$methodName'") - - val params = mkParamsImpl(lhsTpe.member(methodName).asMethod, rec) - q"$lhs.$methodName(...$params)" - } - def mkRecordImpl(rec: Tree*): Tree = { def mkElem(key: Type, value: Tree): Tree = q"$value.asInstanceOf[${FieldType(key, value.tpe.widen)}]" @@ -94,14 +55,4 @@ class RecordMacros(val c: whitebox.Context) extends CaseClassMacros { q"$hconsValueTree(${promoteElem(elem)}, $acc)" } } - - def mkParamsImpl[L <: HList](method: MethodSymbol, rec: Expr[L]): List[List[Tree]] = { - val selector = reify(ops.hlist.Selector) - def mkElem(key: Type, value: Tree): Tree = - q"$selector[${rec.actualType}, ${FieldType(key, value.tpe.widen)}].apply($rec)" - - method.paramLists.filterNot(_.forall(_.isImplicit)).map(_.map { p => - mkElem(constantType(nameAsValue(p.name)), q"${p.typeSignature}") - }) - } } diff --git a/core/src/main/scala-3/shapeless/hlists.scala b/core/src/main/scala-3/shapeless/hlists.scala deleted file mode 100644 index 46d801d08..000000000 --- a/core/src/main/scala-3/shapeless/hlists.scala +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2011-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -trait NatProductArgsScalaCompat { - def applyDynamic(method: String)(args: Int*): Any = ??? -} - -trait ProductArgsScalaCompat { - def applyDynamic(method: String)(args: Any*): Any = ??? -} - -trait FromProductArgsScalaCompat { - def applyDynamic(method: String)(hlist: HList): Any = ??? -} - -trait SingletonProductArgsScalaCompat { - def applyDynamic(method: String)(args: Any*): Any = ??? -} diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala index af6ded925..29c838e09 100644 --- a/core/src/main/scala-3/shapeless/records.scala +++ b/core/src/main/scala-3/shapeless/records.scala @@ -20,12 +20,3 @@ trait RecordScalaCompat { def applyDynamic(method: String)(rec: Any*): HList = ??? def applyDynamicNamed(method: String)(rec: Any*): HList = ??? } - -trait RecordArgsScalaCompat { - def applyDynamic(method: String)(): Any = ??? - def applyDynamicNamed(method: String)(rec: Any*): Any = ??? -} - -trait FromRecordArgsScalaCompat { - def applyDynamic[L <: HList](method: String)(rec: L): Any = ??? -} diff --git a/core/src/main/scala/shapeless/alacarte.scala b/core/src/main/scala/shapeless/alacarte.scala index 58bf32e45..374741a0e 100644 --- a/core/src/main/scala/shapeless/alacarte.scala +++ b/core/src/main/scala/shapeless/alacarte.scala @@ -117,9 +117,12 @@ trait CopyFacet extends CaseClassFacet { val ops: CopyOps + /* + TODO RecordArgs gone trait CopyMethods extends RecordArgs { self: C => def copyRecord[R <: HList](rec: R)(implicit merger: ops.CopyMerger[R]): C = ops.copy(this, rec) } + */ } trait ToStringFacet extends ProductFacet { @@ -154,7 +157,7 @@ trait DefaultCaseClassDefns trait CaseClass extends ProductMethods with PolymorphicEqualityMethods - with CopyMethods + // TODO Gone with CopyMethods with ToStringMethods { self: C => } val ops: CaseClassOps diff --git a/core/src/main/scala/shapeless/hlists.scala b/core/src/main/scala/shapeless/hlists.scala index fd1949c6d..8de673a8d 100644 --- a/core/src/main/scala/shapeless/hlists.scala +++ b/core/src/main/scala/shapeless/hlists.scala @@ -16,8 +16,6 @@ package shapeless -import scala.language.dynamics - import scala.annotation.tailrec /** @@ -161,91 +159,3 @@ object HList { loop(l, i, HNil) } } - -/** - * Trait supporting mapping dynamic argument lists of Ints to HList of Nat arguments. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.method(1, 2, 3) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.methodProduct(_1 :: _2 :: _3) - * }}} - * - * ie. the arguments are rewritten as HList elements of Nat and the application is - * rewritten to an application of an implementing method (identified by the - * "Product" suffix) which accepts a single HList of Int argument. - * - * @author Andreas Koestler - */ - -trait NatProductArgs extends Dynamic with NatProductArgsScalaCompat -/** - * Trait supporting mapping dynamic argument lists to HList arguments. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.method(23, "foo", true) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.methodProduct(23 :: "foo" :: true) - * }}} - * - * ie. the arguments are rewritten as HList elements and the application is - * rewritten to an application of an implementing method (identified by the - * "Product" suffix) which accepts a single HList argument. - * - */ -trait ProductArgs extends Dynamic with ProductArgsScalaCompat - -/** - * Trait supporting mapping HList arguments to argument lists, inverse of ProductArgs. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.methodProduct(23 :: "foo" :: true) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.method(23, "foo", true) - * }}} - * - * ie. the HList argument is used to obtain arguments for a target method - * (the called method named minus the "Product" suffix) in sequence and the application - * is rewritten to an application of the target method - * - */ -trait FromProductArgs extends Dynamic with FromProductArgsScalaCompat - -/** - * Trait supporting mapping dynamic argument lists to singleton-typed HList arguments. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.method(23, "foo", true) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.methodProduct(23.narrow :: "foo".narrow :: true.narrow) - * }}} - * - * ie. the arguments are rewritten as singleton-typed HList elements and the - * application is rewritten to an application of an implementing method (identified by the - * "Product" suffix) which accepts a single HList argument. - */ -trait SingletonProductArgs extends Dynamic with SingletonProductArgsScalaCompat diff --git a/core/src/main/scala/shapeless/records.scala b/core/src/main/scala/shapeless/records.scala index f696e436a..9d8b58d73 100644 --- a/core/src/main/scala/shapeless/records.scala +++ b/core/src/main/scala/shapeless/records.scala @@ -54,46 +54,3 @@ object record { */ object Record extends Dynamic with RecordScalaCompat } - -/** - * Trait supporting mapping named argument lists to record arguments. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.method(x = 23, y = "foo", z = true) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.methodRecord("x" ->> 23 :: "y" ->> "foo", "z" ->> true) - * }}} - * - * ie. the named arguments are rewritten as record fields with the argument name - * encoded as a singleton-typed `Symbol` and the application is rewritten to an - * application of an implementing method (identified by the "Record" suffix) which - * accepts a single record argument. - */ -trait RecordArgs extends Dynamic with RecordArgsScalaCompat - -/** - * Trait supporting mapping record arguments to named argument lists, inverse of RecordArgs. - * - * Mixing in this trait enables method applications of the form, - * - * {{{ - * lhs.methodRecord("x" ->> 23 :: "y" ->> "foo" :: "z" ->> true :: HNil) - * }}} - * - * to be rewritten as, - * - * {{{ - * lhs.method(x = 23, y = "foo", z = true) - * }}} - * - * ie. the record argument is used to look up arguments for a target method - * (the called method named minus the "Record" suffix) by name and type and the application - * is rewritten to an application of the target method - */ -trait FromRecordArgs extends Dynamic with FromRecordArgsScalaCompat diff --git a/core/src/main/scala/shapeless/syntax/hlists.scala b/core/src/main/scala/shapeless/syntax/hlists.scala index fd70aa22a..aedeca462 100644 --- a/core/src/main/scala/shapeless/syntax/hlists.scala +++ b/core/src/main/scala/shapeless/syntax/hlists.scala @@ -117,18 +117,8 @@ final class HListOps[L <: HList](l : L) extends Serializable { */ def select[U](implicit selector : Selector[L, U]) : U = selector(l) - /** - * Returns the elements of this `HList` specified by `Ids`. Available only if there is - * evidence that this `HList` contains all elements specified in `Ids`. - */ - case class SelectManyAux[L <: HList](l: L) extends NatProductArgs { - def applyNatProduct[Ids <: HList](implicit sel: SelectMany[L,Ids]): sel.Out = sel(l) - } - def selectManyType[Ids <: HList](implicit sel: SelectMany[L, Ids]): sel.Out = sel(l) - def selectMany = SelectManyAux(l) - /** * Returns the elements of this `HList` specified by the range of ids in [A,B[ * Available only if there is evidence that this `HList` contains all elements in that range From 7eb3372f827e78c86c9f5184ce893b79810586e5 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 22:54:01 +0200 Subject: [PATCH 06/32] Remove lazy leftover --- core/src/main/scala-3/shapeless/lazy.scala | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 core/src/main/scala-3/shapeless/lazy.scala diff --git a/core/src/main/scala-3/shapeless/lazy.scala b/core/src/main/scala-3/shapeless/lazy.scala deleted file mode 100644 index 6644b6495..000000000 --- a/core/src/main/scala-3/shapeless/lazy.scala +++ /dev/null @@ -1,5 +0,0 @@ -package shapeless - -trait LazyScalaCompat[+T] { - lazy val value: T -} From adeb26c78fe073c563fe6e20b3fc3805c9f0c33c Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 23:03:35 +0200 Subject: [PATCH 07/32] Implement nat.ToInt --- core/src/main/scala-3/shapeless/ops/nat.scala | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala-3/shapeless/ops/nat.scala b/core/src/main/scala-3/shapeless/ops/nat.scala index d0b2b765e..296f15ae2 100644 --- a/core/src/main/scala-3/shapeless/ops/nat.scala +++ b/core/src/main/scala-3/shapeless/ops/nat.scala @@ -17,6 +17,13 @@ package shapeless package ops +import scala.compiletime + trait ToIntScalaCompat { - implicit def toIntSuccM[N <: Nat]: nat.ToInt[N] = ??? + type NatToInt[N <: Nat] <: Int = N match { + case _0 => 0 + case Succ[n] => scala.compiletime.ops.int.S[NatToInt[n]] + } + + given toIntSuccM[N <: Nat](using v: ValueOf[NatToInt[N]]): nat.ToInt[N] = new nat.ToInt.Inst[N](v.value) } From d04f95be735d677c12cc2d73bcac51463c67deed Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 21 Jun 2021 23:54:34 +0200 Subject: [PATCH 08/32] Implement Nat implicit conversion --- core/src/main/scala-3/shapeless/nat.scala | 18 +++++++++++++++++- core/src/main/scala-3/shapeless/ops/nat.scala | 7 +------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/core/src/main/scala-3/shapeless/nat.scala b/core/src/main/scala-3/shapeless/nat.scala index 674bb98d1..767747dc7 100644 --- a/core/src/main/scala-3/shapeless/nat.scala +++ b/core/src/main/scala-3/shapeless/nat.scala @@ -16,6 +16,22 @@ package shapeless +import scala.compiletime.ops.int.S + trait NatScalaCompat { - implicit def apply(i: Int): Nat = ??? + type NatToInt[N <: Nat] <: Int = N match { + case _0 => 0 + case Succ[n] => scala.compiletime.ops.int.S[NatToInt[n]] + } + + type IntToNat[N <: Int] <: Nat = N match { + case 0 => _0 + case S[n] => Succ[IntToNat[n]] + } + + //Transparent gives better types here + transparent inline implicit def apply(inline i: Int): Nat = + if i < 0 then compiletime.error("Can't convert value less than 0 to nat") + else if i == 0 then (new _0).asInstanceOf[IntToNat[i.type]] + else (new Succ).asInstanceOf[IntToNat[i.type]] } diff --git a/core/src/main/scala-3/shapeless/ops/nat.scala b/core/src/main/scala-3/shapeless/ops/nat.scala index 296f15ae2..9da46a853 100644 --- a/core/src/main/scala-3/shapeless/ops/nat.scala +++ b/core/src/main/scala-3/shapeless/ops/nat.scala @@ -20,10 +20,5 @@ package ops import scala.compiletime trait ToIntScalaCompat { - type NatToInt[N <: Nat] <: Int = N match { - case _0 => 0 - case Succ[n] => scala.compiletime.ops.int.S[NatToInt[n]] - } - - given toIntSuccM[N <: Nat](using v: ValueOf[NatToInt[N]]): nat.ToInt[N] = new nat.ToInt.Inst[N](v.value) + given toIntSuccM[N <: Nat](using v: ValueOf[Nat.NatToInt[N]]): nat.ToInt[N] = new nat.ToInt.Inst[N](v.value) } From 05f9231195ceb565e9a9d1e30c623cffdd06dbd2 Mon Sep 17 00:00:00 2001 From: Katrix Date: Wed, 23 Jun 2021 15:34:06 +0200 Subject: [PATCH 09/32] Basic implementation for Generic and LabelledGeneric --- build.sbt | 6 +-- .../main/scala-2/shapeless/coproduct.scala | 3 ++ core/src/main/scala-2/shapeless/hlists.scala | 3 ++ .../main/scala-3/shapeless/coproduct.scala | 28 ++++++++++ core/src/main/scala-3/shapeless/generic.scala | 52 +++++++++++++++++-- core/src/main/scala-3/shapeless/hlists.scala | 25 +++++++++ .../src/main/scala-3/shapeless/labelled.scala | 12 ++++- .../scala-3/shapeless/typeoperators.scala | 2 +- core/src/main/scala/shapeless/coproduct.scala | 2 +- core/src/main/scala/shapeless/hlists.scala | 2 +- 10 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 core/src/main/scala-2/shapeless/coproduct.scala create mode 100644 core/src/main/scala-2/shapeless/hlists.scala create mode 100644 core/src/main/scala-3/shapeless/coproduct.scala create mode 100644 core/src/main/scala-3/shapeless/hlists.scala diff --git a/build.sbt b/build.sbt index 58c578a96..e1aee9a0a 100644 --- a/build.sbt +++ b/build.sbt @@ -2,15 +2,15 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject val Scala213 = "2.13.6" -val scala3 = "3.0.0" +val Scala3 = "3.0.0" commonSettings noPublishSettings crossScalaVersions := Nil ThisBuild / organization := "com.chuusai" -ThisBuild / scalaVersion := Scala213 -ThisBuild / crossScalaVersions := Seq(Scala213, scala3) +ThisBuild / scalaVersion := Scala3 +ThisBuild / crossScalaVersions := Seq(Scala213, Scala3) ThisBuild / mimaFailOnNoPrevious := false // GHA configuration diff --git a/core/src/main/scala-2/shapeless/coproduct.scala b/core/src/main/scala-2/shapeless/coproduct.scala new file mode 100644 index 000000000..1aea78d13 --- /dev/null +++ b/core/src/main/scala-2/shapeless/coproduct.scala @@ -0,0 +1,3 @@ +package shapeless + +trait CoproductScalaCompat diff --git a/core/src/main/scala-2/shapeless/hlists.scala b/core/src/main/scala-2/shapeless/hlists.scala new file mode 100644 index 000000000..4d95d26f8 --- /dev/null +++ b/core/src/main/scala-2/shapeless/hlists.scala @@ -0,0 +1,3 @@ +package shapeless + +trait HListScalaCompat diff --git a/core/src/main/scala-3/shapeless/coproduct.scala b/core/src/main/scala-3/shapeless/coproduct.scala new file mode 100644 index 000000000..4a31c5525 --- /dev/null +++ b/core/src/main/scala-3/shapeless/coproduct.scala @@ -0,0 +1,28 @@ +package shapeless + +trait CoproductScalaCompat { + + type CoproductToTuple[C <: Coproduct] <: scala.Tuple = C match { + case CNil => EmptyTuple + case h :+: t => h *: CoproductToTuple[t] + } + type TupleToCoproduct[T <: scala.Tuple] <: Coproduct = T match { + case EmptyTuple => CNil + case h *: t => h :+: TupleToCoproduct[t] + } + + type HListToCoproduct[L <: HList] <: Coproduct = L match { + case HNil => CNil + case h :: t => h :+: t + } + + def extractCoproduct[C <: Coproduct](coproduct: C): scala.Tuple.Union[CoproductToTuple[C]] = coproduct match { + case Inl(head) => head.asInstanceOf + case Inr(tail) => extractCoproduct(tail.asInstanceOf) + case err: CNil => err.impossible + } + + def coproductFromOrdinal[T <: scala.Tuple](a: scala.Tuple.Union[T], ordinal: Int): TupleToCoproduct[T] = + if ordinal == 0 then Inl(a).asInstanceOf + else Inr(coproductFromOrdinal(a, ordinal - 1)).asInstanceOf +} diff --git a/core/src/main/scala-3/shapeless/generic.scala b/core/src/main/scala-3/shapeless/generic.scala index 7dd1136fe..07a590dd4 100644 --- a/core/src/main/scala-3/shapeless/generic.scala +++ b/core/src/main/scala-3/shapeless/generic.scala @@ -16,24 +16,66 @@ package shapeless +import scala.deriving._ + trait GenericScalaCompat { - implicit def materialize[T, R]: Generic.Aux[T, R] = ??? + given materializeProduct[T <: Product]( + using m: scala.deriving.Mirror.ProductOf[T] + ): Generic.Aux[T, HList.TupleToHList[m.MirroredElemTypes]] = + new Generic[T] { + override type Repr = HList.TupleToHList[m.MirroredElemTypes] + + override def to(t: T): Repr = HList.tupleToHList(scala.Tuple.fromProductTyped(t)) + + override def from(r: Repr): T = m.fromProduct(HList.hListToTuple(r)) + } + + given materializeSum[T]( + using m: scala.deriving.Mirror.SumOf[T], + ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, + ): Generic.Aux[T, Coproduct.TupleToCoproduct[m.MirroredElemTypes]] = + new Generic[T] { + override type Repr = Coproduct.TupleToCoproduct[m.MirroredElemTypes] + + override def to(t: T): Repr = Coproduct.coproductFromOrdinal(t.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes]], m.ordinal(t)) + + override def from(r: Repr): T = ev(Coproduct.extractCoproduct(r)) + } } trait LabelledGenericScalaCompat { - implicit def materialize[T, R]: LabelledGeneric.Aux[T, R] = ??? + type MakeFieldsProduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: HList = (Types, Labels) match { + case (EmptyTuple, EmptyTuple) => HNil + case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :: MakeFieldsProduct[types, labels] + } + + type MakeFieldsCoproduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: Coproduct = (Types, Labels) match { + case (EmptyTuple, EmptyTuple) => CNil + case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :+: MakeFieldsCoproduct[types, labels] + } + + given materializeProduct[T <: Product]( + using m: scala.deriving.Mirror.ProductOf[T] + ): LabelledGeneric.Aux[T, MakeFieldsProduct[m.MirroredElemTypes, m.MirroredElemLabels]] = + LabelledGeneric.unsafeInstance(Generic.materializeProduct) + + given materializeSum[T]( + using m: scala.deriving.Mirror.SumOf[T], + ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, + ): LabelledGeneric.Aux[T, MakeFieldsCoproduct[m.MirroredElemTypes, m.MirroredElemLabels]] = + LabelledGeneric.unsafeInstance(Generic.materializeSum) } trait IsTupleScalaCompat { - implicit def apply[T]: IsTuple[T] = ??? + given[T <: scala.Tuple]: IsTuple[T] = new IsTuple[T] } trait HasProductGenericScalaCompat { - implicit def apply[T]: HasProductGeneric[T] = ??? + given [T](using Mirror.ProductOf[T]): HasProductGeneric[T] = new HasProductGeneric[T] } trait HasCoproductGenericScalaCompat { - implicit def apply[T]: HasCoproductGeneric[T] = ??? + given [T](using Mirror.SumOf[T]): HasCoproductGeneric[T] = new HasCoproductGeneric[T] } diff --git a/core/src/main/scala-3/shapeless/hlists.scala b/core/src/main/scala-3/shapeless/hlists.scala new file mode 100644 index 000000000..8ad3eef9b --- /dev/null +++ b/core/src/main/scala-3/shapeless/hlists.scala @@ -0,0 +1,25 @@ +package shapeless + +trait HListScalaCompat { + + type TupleToHList[T <: scala.Tuple] <: HList = T match { + case EmptyTuple => HNil + case h *: t => h :: TupleToHList[t] + } + + //TODO: tailrec + def tupleToHList[T <: scala.Tuple](tuple: T): TupleToHList[T] = tuple match { + case _: EmptyTuple => HNil + case cons: *:[h, t] => ::(cons.head, tupleToHList(cons.tail)) + } + + type HListToTuple[L <: HList] <: scala.Tuple = L match { + case HNil => EmptyTuple + case h :: t => h *: HListToTuple[t] + } + //TODO: tailrec + def hListToTuple[L <: HList](hlist: L): HListToTuple[L] = hlist match { + case _: HNil => EmptyTuple + case cons: ::[h, t] => (cons.head *: hListToTuple(cons.tail)) + } +} diff --git a/core/src/main/scala-3/shapeless/labelled.scala b/core/src/main/scala-3/shapeless/labelled.scala index 70527df20..1c993340a 100644 --- a/core/src/main/scala-3/shapeless/labelled.scala +++ b/core/src/main/scala-3/shapeless/labelled.scala @@ -16,7 +16,17 @@ package shapeless +import scala.deriving._ + trait LabellingScalaCompat { - implicit def mkLabelling[T]: Labelling[T] = ??? + inline given [T](using m: Mirror.Of[T]): Labelling.Aux[T, HList.TupleToHList[m.MirroredElemLabels]] = { + val tuple = scala.compiletime.package$package.constValueTuple[m.MirroredElemLabels] + val res = HList.tupleToHList(tuple) + + new Labelling[T] { + override type Out = HList.TupleToHList[m.MirroredElemLabels] + override def apply(): Out = res + } + } } diff --git a/core/src/main/scala-3/shapeless/typeoperators.scala b/core/src/main/scala-3/shapeless/typeoperators.scala index 42a8d5d3b..a624face7 100644 --- a/core/src/main/scala-3/shapeless/typeoperators.scala +++ b/core/src/main/scala-3/shapeless/typeoperators.scala @@ -1,5 +1,5 @@ package shapeless trait theScalaCompat { - transparent inline def summon[T](using inline x: T): x.type = x + transparent inline def the[T](using inline x: T): x.type = x } diff --git a/core/src/main/scala/shapeless/coproduct.scala b/core/src/main/scala/shapeless/coproduct.scala index 8f847cc9c..3877b65ef 100644 --- a/core/src/main/scala/shapeless/coproduct.scala +++ b/core/src/main/scala/shapeless/coproduct.scala @@ -116,7 +116,7 @@ sealed trait CNil extends Coproduct { def impossible: Nothing } -object Coproduct { +object Coproduct extends CoproductScalaCompat { import ops.coproduct.Inject import ops.coproduct.RuntimeInject import syntax.CoproductOps diff --git a/core/src/main/scala/shapeless/hlists.scala b/core/src/main/scala/shapeless/hlists.scala index 8de673a8d..19cba2ce6 100644 --- a/core/src/main/scala/shapeless/hlists.scala +++ b/core/src/main/scala/shapeless/hlists.scala @@ -54,7 +54,7 @@ sealed trait HNil extends HList { */ case object HNil extends HNil -object HList { +object HList extends HListScalaCompat { import ops.hlist._ import syntax.HListOps From 1540eeaf0bcc3a24cdf16af8da057cfdeb3f9f25 Mon Sep 17 00:00:00 2001 From: Katrix Date: Wed, 23 Jun 2021 15:51:07 +0200 Subject: [PATCH 10/32] Change the encoding of FieldType --- core/src/main/scala/shapeless/labelled.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala/shapeless/labelled.scala b/core/src/main/scala/shapeless/labelled.scala index 3b84a967a..c9f642af4 100644 --- a/core/src/main/scala/shapeless/labelled.scala +++ b/core/src/main/scala/shapeless/labelled.scala @@ -20,7 +20,7 @@ object labelled { /** The type of fields with keys of singleton type `K` and value type `V`. */ type FieldType[K, +V] = V with KeyTag[K, V] - trait KeyTag[K, +V] extends Any + type KeyTag[K, +V] /** Yields a result encoding the supplied value with the singleton type `K` of its key. */ def field[K]: FieldBuilder[K] = new FieldBuilder(true) From d8c783de039521b8beba02cb70f24f492ee1d43f Mon Sep 17 00:00:00 2001 From: Katrix Date: Wed, 23 Jun 2021 16:20:03 +0200 Subject: [PATCH 11/32] Editor artifact sneaking through from implementing Generic --- core/src/main/scala-3/shapeless/labelled.scala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala-3/shapeless/labelled.scala b/core/src/main/scala-3/shapeless/labelled.scala index 1c993340a..fb5df6a86 100644 --- a/core/src/main/scala-3/shapeless/labelled.scala +++ b/core/src/main/scala-3/shapeless/labelled.scala @@ -17,11 +17,12 @@ package shapeless import scala.deriving._ +import scala.compiletime._ trait LabellingScalaCompat { inline given [T](using m: Mirror.Of[T]): Labelling.Aux[T, HList.TupleToHList[m.MirroredElemLabels]] = { - val tuple = scala.compiletime.package$package.constValueTuple[m.MirroredElemLabels] + val tuple = constValueTuple[m.MirroredElemLabels] val res = HList.tupleToHList(tuple) new Labelling[T] { From 42d38f234ef280b20c20757f394f103b6f64da1b Mon Sep 17 00:00:00 2001 From: Katrix Date: Wed, 23 Jun 2021 17:00:23 +0200 Subject: [PATCH 12/32] Better type lambdas in Generic1 --- .../src/main/scala-3/shapeless/generic1.scala | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index 2639447ae..f187f20a6 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -18,9 +18,9 @@ package shapeless trait Generic1ScalaCompat { - implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] = ??? + implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, [t[_]] =>> FR[t, U]] = ??? - implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[U, t] })#λ] = ??? + implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, [t[_]] =>> FR[U, t]] = ??? } trait Generic10ScalaCompat { @@ -29,13 +29,13 @@ trait Generic10ScalaCompat { trait IsHCons1ScalaCompat { - implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = ??? + implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, [t[_]] =>> FH[t, U], FT] = ??? - implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = ??? + implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, [t[_]] =>> FH[U, t], FT] = ??? - implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = ??? + implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, [t[_]] =>> FT[t, U]] = ??? - implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = ??? + implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, [t[_]] =>> FT[U, t]] = ??? } trait IsHCons10ScalaCompat { @@ -44,13 +44,13 @@ trait IsHCons10ScalaCompat { trait IsCCons1ScalaCompat { - implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = ??? + implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FH[t, U], FT] = ??? - implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[U, t] })#λ, FT] = ??? + implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FT[U, t], FT] = ??? - implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[t, U] })#λ] = ??? + implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, [t[_]] =>> FT[t, U]] = ??? - implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, ({ type λ[t[_]] = FT[U, t] })#λ] = ??? + implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, [t[_]] =>> FT[U, t]] = ??? } trait IsCCons10ScalaCompat { @@ -59,13 +59,13 @@ trait IsCCons10ScalaCompat { trait Split1ScalaCompat { - implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] = ??? + implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, [t[_]] =>> FO[t, U], FI] = ??? - implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[U, t] })#λ, FI] = ??? + implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, [t[_]] =>> FO[U, t], FI] = ??? - implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[t, U] })#λ] = ??? + implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, [t[_]] =>> FI[t, U]] = ??? - implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, ({ type λ[t[_]] = FI[U, t] })#λ] = ??? + implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, [t[_]] =>> FI[U, t]] = ??? } trait Split10ScalaCompat { From 8ddb9903beccba29f28e22b1feb417f1bc97edc1 Mon Sep 17 00:00:00 2001 From: Katrix Date: Sat, 26 Jun 2021 19:51:32 +0200 Subject: [PATCH 13/32] Oops --- core/src/main/scala-3/shapeless/generic1.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index f187f20a6..0a3ff0b4e 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -46,7 +46,7 @@ trait IsCCons1ScalaCompat { implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FH[t, U], FT] = ??? - implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FT[U, t], FT] = ??? + implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FH[U, t], FT] = ??? implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, [t[_]] =>> FT[t, U]] = ??? From 248afb4406f1ab275b6716d4a907290c1ac5921f Mon Sep 17 00:00:00 2001 From: Katrix Date: Sat, 26 Jun 2021 19:53:05 +0200 Subject: [PATCH 14/32] Add type to easily create records and discriminated unions --- core/src/main/scala/shapeless/labelled.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/scala/shapeless/labelled.scala b/core/src/main/scala/shapeless/labelled.scala index c9f642af4..e7653ce05 100644 --- a/core/src/main/scala/shapeless/labelled.scala +++ b/core/src/main/scala/shapeless/labelled.scala @@ -22,6 +22,8 @@ object labelled { type FieldType[K, +V] = V with KeyTag[K, V] type KeyTag[K, +V] + type ->>[K, +V] = FieldType[K, V] + /** Yields a result encoding the supplied value with the singleton type `K` of its key. */ def field[K]: FieldBuilder[K] = new FieldBuilder(true) class FieldBuilder[K](private val dummy: Boolean) extends AnyVal { From 81453b8cb8c107218acd791645b1dfacf4838361 Mon Sep 17 00:00:00 2001 From: Katrix Date: Sat, 26 Jun 2021 22:42:36 +0200 Subject: [PATCH 15/32] Add record and union construction --- core/src/main/scala-3/shapeless/records.scala | 48 ++++++++++++++++++- core/src/main/scala-3/shapeless/unions.scala | 41 +++++++++++++++- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala index 29c838e09..dc773f4c0 100644 --- a/core/src/main/scala-3/shapeless/records.scala +++ b/core/src/main/scala-3/shapeless/records.scala @@ -16,7 +16,51 @@ package shapeless +import shapeless.labelled.FieldType + +import scala.compiletime._ +import scala.quoted._ + trait RecordScalaCompat { - def applyDynamic(method: String)(rec: Any*): HList = ??? - def applyDynamicNamed(method: String)(rec: Any*): HList = ??? + inline def applyDynamic(inline method: String)(inline rec: (String, Any)*): HNil = + //inline if method != "apply" then ??? //error(s"this method must be called as 'apply' not $method") + //else inline if rec.nonEmpty then ??? //error("this method must be called with named arguments") + /*else*/ HNil + + transparent inline def applyDynamicNamed(inline method: String)(inline rec: (String, Any)*): HList = + ${ RecordScalaCompat.applyDynamicNamedImpl('method)('rec) } +} +object RecordScalaCompat { + def applyDynamicNamedImpl(method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[HList] = { + import quotes.reflect.report + val methodString = method.valueOrError + if methodString != "apply" then + report.error(s"this method must be called as 'apply' not '$methodString'") + '{???} + + rec match { + case Varargs(values) => + def transform[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[(String, Any)]]): Expr[HList] = + rest match { + case Nil => acc + case Seq('{($keyExpr: String, $value: tp)}, tail*) => + import quotes.reflect._ + keyExpr.asTerm match { + case Literal(const) => ConstantType(const).asType + } match { + case '[keyTpe] => transform('{$value.asInstanceOf[FieldType[keyTpe, tp]] :: $acc}, tail) + } + + case _ => + report.error("Got invalid arguments in varargs") + '{???} + } + + transform('{HNil}, values.reverse) + + case _ => + report.error("this method must be called with vararg arguments") + '{???} + } + } } diff --git a/core/src/main/scala-3/shapeless/unions.scala b/core/src/main/scala-3/shapeless/unions.scala index bde40385d..24261d64d 100644 --- a/core/src/main/scala-3/shapeless/unions.scala +++ b/core/src/main/scala-3/shapeless/unions.scala @@ -16,6 +16,45 @@ package shapeless +import shapeless.labelled.FieldType + +import scala.quoted._ + trait UnionScalaCompat { - def applyDynamicNamed[U <: Coproduct](method: String)(elems: Any*): U = ??? + transparent inline def applyDynamicNamed[U <: Coproduct](inline method: String)(inline rec: (String, Any)*): U = + ${ UnionScalaCompat.applyDynamicNamedImpl[U]('method)('rec) } +} +object UnionScalaCompat { + def applyDynamicNamedImpl[U <: Coproduct: Type](method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[U] = { + import quotes.reflect.report + val methodString = method.valueOrError + if methodString != "apply" then + report.error(s"this method must be called as 'apply' not '$methodString'") + '{???} + + rec match { + case Varargs(Seq('{($keyExpr: String, $value: tp)})) => + import quotes.reflect._ + + keyExpr.asTerm match { + case Literal(const) => ConstantType(const).asType + } match { + case '[keyTpe] => + Expr.summon[ops.coproduct.Inject[U, FieldType[keyTpe, tp]]] match { + case Some(injectExpr) => '{$injectExpr($value.asInstanceOf[FieldType[keyTpe, tp]])} + case None => + report.error("Can not inject into coproduct") + '{???} + } + } + + case Varargs(_) => + report.error("only one branch of a union may be inhabited") + '{???} + + case _ => + report.error("this method must be called with vararg arguments") + '{???} + } + } } From 6b8376f49e098fd0fb5b9479957a825d6cc65e27 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 5 Jul 2021 20:11:18 +0200 Subject: [PATCH 16/32] Implement most of Generic1 --- .../src/main/scala-3/shapeless/generic1.scala | 213 ++++++++++++++++-- 1 file changed, 191 insertions(+), 22 deletions(-) diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index 0a3ff0b4e..f4e5ce835 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -16,56 +16,225 @@ package shapeless -trait Generic1ScalaCompat { +import scala.deriving.Mirror + +type Apply10[FR[_[_], _[_]], U[_]] = [t[_]] =>> FR[t, U] +type Apply11[FR[_[_], _[_]], U[_]] = [t[_]] =>> FR[U, t] - implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, [t[_]] =>> FR[t, U]] = ??? +//Type to make application more explicit in the presence of Apply10 and Apply11 +type ApplyF[F[_[_]], A[_]] = F[A] - implicit def mkGeneric11[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, [t[_]] =>> FR[U, t]] = ??? +type ElemTypesToHList[ElemTypes[_] <: scala.Tuple] = [Z] =>> HList.TupleToHList[ElemTypes[Z]] +type ElemTypesToCoproduct[ElemTypes[_] <: scala.Tuple] = [Z] =>> Coproduct.TupleToCoproduct[ElemTypes[Z]] + +type MirrorOf1Product[A[_] <: Product] = Mirror.Product { + type MirroredType[Z] = A[Z] + type MirroredMonoType = A[Any] + type MirroredElemTypes[Z] <: scala.Tuple } -trait Generic10ScalaCompat { - implicit def apply[T[_], FR[_[_]]]: Generic1[T, FR] = ??? +type MirrorOf1Sum[A[_]] = Mirror.Sum { + type MirroredType[Z] = A[Z] + type MirroredMonoType = A[Any] + type MirroredElemTypes[Z] <: scala.Tuple } -trait IsHCons1ScalaCompat { +trait Generic1ScalaCompat { + + given mkGeneric10Product[T[_] <: Product, U[_], FR[_[_], _[_]]]( + using m: MirrorOf1Product[T], + frr: => ApplyF[Apply10[FR, U], ElemTypesToHList[m.MirroredElemTypes]] + ): Generic1.Aux[T, Apply10[FR, U], ElemTypesToHList[m.MirroredElemTypes]] = + Generic1.fromProduct[T, Apply10[FR, U]] + + given mkGeneric11Product[T[_] <: Product, U[_], FR[_[_], _[_]]]( + using m: MirrorOf1Product[T], + frr: => ApplyF[Apply11[FR, U], ElemTypesToHList[m.MirroredElemTypes]] + ): Generic1.Aux[T, Apply11[FR, U], ElemTypesToHList[m.MirroredElemTypes]] = + Generic1.fromProduct[T, Apply11[FR, U]] + + given mkGeneric10Sum[T[_], U[_], FR[_[_], _[_]]]( + using m: MirrorOf1Sum[T], + frr: => ApplyF[Apply10[FR, U], ElemTypesToCoproduct[m.MirroredElemTypes]] + ): Generic1.Aux[T, Apply10[FR, U], ElemTypesToCoproduct[m.MirroredElemTypes]] = + Generic1.fromSum[T, Apply10[FR, U]] + + given mkGeneric11Sum[T[_], U[_], FR[_[_], _[_]]]( + using m: MirrorOf1Sum[T], + frr: => ApplyF[Apply11[FR, U], ElemTypesToCoproduct[m.MirroredElemTypes]] + ): Generic1.Aux[T, Apply11[FR, U], ElemTypesToCoproduct[m.MirroredElemTypes]] = + Generic1.fromSum[T, Apply11[FR, U]] +} + +trait Generic10ScalaCompat { + + given fromProduct[A[_] <: Product, FR[_[_]]]( + using m: MirrorOf1Product[A], + frr: => ApplyF[FR, ElemTypesToHList[m.MirroredElemTypes]] + ): Generic1.Aux[A, FR, ElemTypesToHList[m.MirroredElemTypes]] = new Generic1[A, FR] { + override type R[Z] = HList.TupleToHList[m.MirroredElemTypes[Z]] + + override def to[Z](ft: A[Z]): R[Z] = + HList.tupleToHList(scala.Tuple.fromProduct(ft).asInstanceOf[m.MirroredElemTypes[Z]]) + + override def from[Z](rt: R[Z]): A[Z] = + m.fromProduct(HList.hListToTuple(rt)).asInstanceOf[A[Z]] - implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, [t[_]] =>> FH[t, U], FT] = ??? + override def mkFrr: FR[R] = frr + } - implicit def mkIsHCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, [t[_]] =>> FH[U, t], FT] = ??? + given fromSum[A[_], FR[_[_]]]( + using m: MirrorOf1Sum[A], + frr: => ApplyF[FR, ElemTypesToCoproduct[m.MirroredElemTypes]] + ): Generic1.Aux[A, FR, ElemTypesToCoproduct[m.MirroredElemTypes]] = new Generic1[A, FR] { + override type R[Z] = Coproduct.TupleToCoproduct[m.MirroredElemTypes[Z]] - implicit def mkIsHCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, [t[_]] =>> FT[t, U]] = ??? + override def to[Z](ft: A[Z]): R[Z] = + Coproduct.coproductFromOrdinal(ft.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes[Z]]], m.ordinal(ft.asInstanceOf[m.MirroredMonoType])) - implicit def mkIsHCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsHCons1[L, FH, [t[_]] =>> FT[U, t]] = ??? + override def from[Z](rt: R[Z]): A[Z] = + Coproduct.extractCoproduct(rt).asInstanceOf[A[Z]] + + override def mkFrr: FR[R] = frr + } } -trait IsHCons10ScalaCompat { - implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = ??? +type Head[T <: scala.Tuple] = T match { + case h *: _ => h } -trait IsCCons1ScalaCompat { +type Tail[T <: scala.Tuple] <: scala.Tuple = T match { + case _ *: t => t +} - implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FH[t, U], FT] = ??? +type HeadElemTypes[ElemTypes[_] <: scala.Tuple] = [Z] =>> Head[ElemTypes[Z]] - implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, [t[_]] =>> FH[U, t], FT] = ??? +type TailElemTypesHCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> HList.TupleToHList[Tail[ElemTypes[Z]]] - implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, [t[_]] =>> FT[t, U]] = ??? +trait IsHCons1ScalaCompat { + + given mkIsHCons10[L[_] <: Product, FH[_[_], _[_]], U[_], FT[_[_]]]( + using m: MirrorOf1Product[L], + fhh: => ApplyF[Apply10[FH, U], HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], + ): IsHCons1.Aux[L, Apply10[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = + IsHCons1.fromProduct[L, Apply10[FH, U], FT] + + given mkIsHCons11[L[_] <: Product, FH[_[_], _[_]], U[_], FT[_[_]]]( + using m: MirrorOf1Product[L], + fhh: => ApplyF[Apply11[FH, U], HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], + ): IsHCons1.Aux[L, Apply11[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = + IsHCons1.fromProduct[L, Apply11[FH, U], FT] + + given mkIsHCons12[L[_] <: Product, FH[_[_]], FT[_[_], _[_]], U[_]]( + using m: MirrorOf1Product[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[Apply10[FT, U], TailElemTypesHCons[m.MirroredElemTypes]], + ): IsHCons1.Aux[L, FH, Apply10[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = + IsHCons1.fromProduct[L, FH, Apply10[FT, U]] + + given mkIsHCons13[L[_] <: Product, FH[_[_]], FT[_[_], _[_]], U[_]]( + using m: MirrorOf1Product[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[Apply11[FT, U], TailElemTypesHCons[m.MirroredElemTypes]], + ): IsHCons1.Aux[L, FH, Apply11[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = + IsHCons1.fromProduct[L, FH, Apply11[FT, U]] +} + +trait IsHCons10ScalaCompat { + given fromProduct[L[_] <: Product, FH[_[_]], FT[_[_]]]( + using m: MirrorOf1Product[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], + ): IsHCons1.Aux[L, FH, FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = new IsHCons1[L, FH, FT] { + override type H[Z] = Head[m.MirroredElemTypes[Z]] + override type T[Z] = HList.TupleToHList[Tail[m.MirroredElemTypes[Z]]] + + override def pack[A](u: (H[A], T[A])): L[A] = { + val t = u._1 *: HList.hListToTuple(u._2) + m.fromProduct(t).asInstanceOf[L[A]] + } + + override def unpack[Z](p: L[Z]): (H[Z], T[Z]) = + //This is safe as the ftt won't be typed correctly if L produces an empty tuple + (scala.Tuple.fromProduct(p): @unchecked) match { + case h *: t => (h.asInstanceOf[H[Z]], HList.tupleToHList(t).asInstanceOf[T[Z]]) + } + + override def mkFhh: FH[H] = fhh + override def mkFtt: FT[T] = ftt + } +} + +type TailElemTypesCCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> Coproduct.TupleToCoproduct[Tail[ElemTypes[Z]]] + +trait IsCCons1ScalaCompat { - implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]: IsCCons1[L, FH, [t[_]] =>> FT[U, t]] = ??? + implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]( + using m: MirrorOf1Sum[L], + fhh: => ApplyF[Apply10[FH, U], HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], + ): IsCCons1.Aux[L, Apply10[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = + IsCCons1.fromSum[L, Apply10[FH, U], FT] + + implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]( + using m: MirrorOf1Sum[L], + fhh: => ApplyF[Apply11[FH, U], HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], + ): IsCCons1.Aux[L, Apply11[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = + IsCCons1.fromSum[L, Apply11[FH, U], FT] + + implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]( + using m: MirrorOf1Sum[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[Apply10[FT, U], TailElemTypesCCons[m.MirroredElemTypes]], + ): IsCCons1.Aux[L, FH, Apply10[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = + IsCCons1.fromSum[L, FH, Apply10[FT, U]] + + implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]( + using m: MirrorOf1Sum[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[Apply11[FT, U], TailElemTypesCCons[m.MirroredElemTypes]], + ): IsCCons1.Aux[L, FH, Apply11[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = + IsCCons1.fromSum[L, FH, Apply11[FT, U]] } trait IsCCons10ScalaCompat { - implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsCCons1[L, FH, FT] = ??? + given fromSum[L[_], FH[_[_]], FT[_[_]]]( + using m: MirrorOf1Sum[L], + fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], + ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], + ): IsCCons1.Aux[L, FH, FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = new IsCCons1[L, FH, FT] { + override type H[Z] = Head[m.MirroredElemTypes[Z]] + override type T[Z] = Coproduct.TupleToCoproduct[Tail[m.MirroredElemTypes[Z]]] + + override def pack[Z](u: Either[H[Z], T[Z]]): L[Z] = u match { + case Left(hz) => hz.asInstanceOf[L[Z]] + case Right(tz) => Coproduct.extractCoproduct(tz).asInstanceOf[L[Z]] + } + + override def unpack[Z](p: L[Z]): Either[H[Z], T[Z]] = { + //TODO: Make sure this is correct + val ordinal = m.ordinal(p.asInstanceOf[m.MirroredMonoType]) + if ordinal == 0 then Left(p.asInstanceOf[H[Z]]) + else Right(Coproduct.coproductFromOrdinal(p.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes[Z]]], ordinal - 1).asInstanceOf[T[Z]]) + } + + override def mkFhh: FH[H] = fhh + override def mkFtt: FT[T] = ftt + } } trait Split1ScalaCompat { - implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, [t[_]] =>> FO[t, U], FI] = ??? + implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, Apply10[FO, U], FI] = ??? - implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, [t[_]] =>> FO[U, t], FI] = ??? + implicit def mkSplit11[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, Apply11[FO, U], FI] = ??? - implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, [t[_]] =>> FI[t, U]] = ??? + implicit def mkSplit12[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, Apply10[FI, U]] = ??? - implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, [t[_]] =>> FI[U, t]] = ??? + implicit def mkSplit13[L[_], FO[_[_]], FI[_[_], _[_]], U[_]]: Split1[L, FO, Apply11[FI, U]] = ??? } trait Split10ScalaCompat { From 3fc4a0a3a8b9c4e169335f915b20fd759a7ee536 Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 6 Jul 2021 16:38:07 +0200 Subject: [PATCH 17/32] Removed `Witness`, `NatWith` and `WitnessWith` --- .../main/scala-2/shapeless/singletons.scala | 82 ------ .../main/scala-3/shapeless/singletons.scala | 9 - core/src/main/scala/shapeless/labelled.scala | 2 +- core/src/main/scala/shapeless/lenses.scala | 4 +- core/src/main/scala/shapeless/nat.scala | 3 + .../main/scala/shapeless/ops/coproduct.scala | 12 +- .../src/main/scala/shapeless/ops/hlists.scala | 6 +- core/src/main/scala/shapeless/ops/maps.scala | 2 +- core/src/main/scala/shapeless/ops/nat.scala | 28 +- .../main/scala/shapeless/ops/records.scala | 12 +- .../src/main/scala/shapeless/ops/unions.scala | 10 +- core/src/main/scala/shapeless/poly.scala | 6 +- .../src/main/scala/shapeless/singletons.scala | 71 ----- .../main/scala/shapeless/syntax/hlists.scala | 4 +- .../main/scala/shapeless/syntax/records.scala | 40 +-- .../scala/shapeless/syntax/singletons.scala | 14 +- .../scala/shapeless/syntax/std/tuples.scala | 4 +- .../main/scala/shapeless/syntax/unions.scala | 4 +- core/src/main/scala/shapeless/typeclass.scala | 4 +- core/src/test/scala/shapeless/generic.scala | 4 +- core/src/test/scala/shapeless/generic1.scala | 4 +- core/src/test/scala/shapeless/hlist.scala | 10 +- core/src/test/scala/shapeless/implicits.scala | 4 +- .../scala/shapeless/labelledgeneric.scala | 4 +- core/src/test/scala/shapeless/lenses.scala | 3 +- core/src/test/scala/shapeless/records.scala | 41 ++- .../src/test/scala/shapeless/singletons.scala | 256 ++---------------- core/src/test/scala/shapeless/typeable.scala | 25 +- core/src/test/scala/shapeless/unions.scala | 31 +-- 29 files changed, 155 insertions(+), 544 deletions(-) diff --git a/core/src/main/scala-2/shapeless/singletons.scala b/core/src/main/scala-2/shapeless/singletons.scala index 0bc3d584b..30f9a6aed 100644 --- a/core/src/main/scala-2/shapeless/singletons.scala +++ b/core/src/main/scala-2/shapeless/singletons.scala @@ -21,19 +21,8 @@ import shapeless.syntax.SingletonOps import scala.language.experimental.macros import scala.reflect.macros.whitebox -trait NatWithScalaCompat { - - implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = - macro SingletonTypeMacros.convertInstanceImplNat[TC] - - implicit def apply2[B, T <: B, TC[_ <: B, _ <: Nat]](i: Int): NatWith[({ type λ[t <: Nat] = TC[T, t] })#λ] = - macro SingletonTypeMacros.convertInstanceImplNat1[B, T, TC] -} - trait WidenScalaCompat { - implicit def apply1[TC[_], T](t: T): WitnessWith.Lt[TC, T] = macro SingletonTypeMacros.convertInstanceImpl1[TC] - implicit def materialize[T, Out]: Widen.Aux[T, Out] = macro SingletonTypeMacros.materializeWiden[T, Out] } @@ -104,24 +93,8 @@ trait SingletonTypeUtils extends ReprTypes { class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils with NatMacroDefns { import c.universe._ - import definitions._ import internal._ - def mkWitness(sTpe: Type, s: Tree): Tree = - q"${reify(Witness)}.mkWitness[$sTpe]($s.asInstanceOf[$sTpe])" - - def mkWitnessWith(tcTpe: Type, sTpe: Type, s: Tree, i: Tree): Tree = { - val witnessWith = reify(WitnessWith) - if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$witnessWith.depInstance[$tcTpe, $sTpe]($s, $i)" - else q"$witnessWith.instance[$tcTpe, $sTpe]($s, $i)" - } - - def mkWitnessNat(tcTpe: Type, nTpe: Type, tc: Tree): Tree = { - val natWith = reify(NatWith) - if (appliedType(tcTpe, AnyValTpe) <:< AnyRefTpe) q"$natWith.depInstance[$tcTpe, $nTpe]($tc)" - else q"$natWith.instance[$tcTpe, $nTpe]($tc)" - } - def mkOps(sTpe: Type, w: Tree): Tree = q"${reify(SingletonOps)}.instance[$sTpe]($w)" @@ -145,11 +118,6 @@ class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils wi case _ => c.abort(c.enclosingPosition, s"Type argument $tpe is not a singleton type") } - def materializeImpl[T: WeakTypeTag]: Tree = { - val tpe = weakTypeOf[T].dealias - mkWitness(tpe, extractSingletonValue(tpe)) - } - def extractResult(value: Tree)(mkResult: (Type, Tree) => Tree): Tree = (value.tpe, value) match { case (tpe @ ConstantType(const), _) => @@ -171,8 +139,6 @@ class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils wi c.abort(c.enclosingPosition, s"Expression $value does not evaluate to a constant or a stable reference value") } - def convertImpl(t: Tree): Tree = extractResult(t)(mkWitness) - def inferInstance(tci: Type): Tree = { val inferred = c.inferImplicitValue(tci) if (inferred == EmptyTree) @@ -180,54 +146,6 @@ class SingletonTypeMacros(val c: whitebox.Context) extends SingletonTypeUtils wi inferred } - def convertInstanceImplNat[TC[_ <: Nat]](i: Tree)( - implicit tcTag: WeakTypeTag[TC[Nothing]] - ): Tree = convertInstanceImplNatAux(i, tcTag.tpe) - - def convertInstanceImplNat1[B, T <: B, TC[_ <: B, _ <: Nat]](i: Tree)( - implicit tTag: WeakTypeTag[T], tcTag: WeakTypeTag[TC[Nothing, Nothing]] - ): Tree = { - val tTpe = tTag.tpe - val tc = tcTag.tpe.typeConstructor - val tcParam = tc.typeParams(1) - val tcTpe = polyType(List(tcParam), appliedType(tc, tTpe, tcParam.asType.toType)) - convertInstanceImplNatAux(i, tcTpe) - } - - def convertInstanceImplNatAux(i: Tree, tcTpe: Type): Tree = { - val nTpe = i match { - case NatLiteral(n) => mkNatTpe(n) - case _ => c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") - } - - val instTpe = appliedType(tcTpe, nTpe) - val iInst = inferInstance(instTpe) - mkWitnessNat(tcTpe, nTpe, iInst) - } - - def convertInstanceImpl1[TC[_]](t: Tree)( - implicit tcTag: WeakTypeTag[TC[_]] - ): Tree = extractResult(t) { (sTpe, value) => - val tc = tcTag.tpe.typeConstructor - val tci = appliedType(tc, sTpe) - val i = inferInstance(tci) - mkWitnessWith(tc, sTpe, value, i) - } - - def convertInstanceImpl2[H, TC2[_ <: H, _], S <: H](t: Tree)( - implicit tc2Tag: WeakTypeTag[TC2[_, _]], sTag: WeakTypeTag[S] - ): Tree = extractResult(t) { (sTpe, value) => - val tc2 = tc2Tag.tpe.typeConstructor - val tparam = tc2.typeParams.last.asType - val tc = polyType(tparam :: Nil, appliedType(tc2, sTag.tpe, tparam.toType)) - val tci = appliedType(tc2, sTag.tpe, sTpe) - val i = inferInstance(tci) - mkWitnessWith(tc, sTpe, value, i) - } - - def mkSingletonOps(t: Tree): Tree = - extractResult(t) { (tpe, tree) => mkOps(tpe, mkWitness(tpe, tree)) } - def materializeWiden[T: WeakTypeTag, Out: WeakTypeTag]: Tree = { val tpe = weakTypeOf[T].dealias val wideTpe = tpe.widen diff --git a/core/src/main/scala-3/shapeless/singletons.scala b/core/src/main/scala-3/shapeless/singletons.scala index 5fed8e034..82d6ce0c9 100644 --- a/core/src/main/scala-3/shapeless/singletons.scala +++ b/core/src/main/scala-3/shapeless/singletons.scala @@ -16,16 +16,7 @@ package shapeless -trait NatWithScalaCompat { - - implicit def apply[TC[_ <: Nat]](i: Any): NatWith[TC] = ??? - - implicit def apply2[B, T <: B, TC[_ <: B, _ <: Nat]](i: Int): NatWith[({ type λ[t <: Nat] = TC[T, t] })#λ] = ??? -} - trait WidenScalaCompat { - implicit def apply1[TC[_], T](t: T): WitnessWith.Lt[TC, T] = ??? - implicit def materialize[T, Out >: T]: Widen.Aux[T, Out] = ??? } diff --git a/core/src/main/scala/shapeless/labelled.scala b/core/src/main/scala/shapeless/labelled.scala index e7653ce05..2b953b6b0 100644 --- a/core/src/main/scala/shapeless/labelled.scala +++ b/core/src/main/scala/shapeless/labelled.scala @@ -61,7 +61,7 @@ trait FieldPoly extends Poly1 { } } - def atField[A](w: Witness): FieldCaseBuilder[A, w.T] = + def atField[A, K <: Singleton](w: K): FieldCaseBuilder[A, K] = new FieldCaseBuilder } diff --git a/core/src/main/scala/shapeless/lenses.scala b/core/src/main/scala/shapeless/lenses.scala index d7913d66a..b0a098fcc 100644 --- a/core/src/main/scala/shapeless/lenses.scala +++ b/core/src/main/scala/shapeless/lenses.scala @@ -39,7 +39,7 @@ trait Lens[S, A] extends LPLens[S, A] { outer => def >>(n: Nat)(implicit mkLens: MkNthFieldLens[A, n.N]): Lens[S, mkLens.Elem] = mkLens() compose this - def >>(k: Witness)(implicit mkLens: MkFieldLens[A, k.T]): Lens[S, mkLens.Elem] = mkLens() compose this + def >>[K <: Singleton](k: K)(implicit mkLens: MkFieldLens[A, K]): Lens[S, mkLens.Elem] = mkLens() compose this def selectDynamic(k: String)( implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, k.type, Nothing] @@ -200,7 +200,7 @@ object OpticDefns { def hlistNthLens[L <: HList, N <: Nat](implicit mkLens: MkHListNthLens[L, N]) = mkLens() - def recordLens[R <: HList](k: Witness)(implicit mkLens: MkRecordSelectLens[R, k.T]) = mkLens() + def recordLens[R <: HList, K <: Singleton](k: K)(implicit mkLens: MkRecordSelectLens[R, K]) = mkLens() } trait OpticComposer[L, R] extends Serializable { diff --git a/core/src/main/scala/shapeless/nat.scala b/core/src/main/scala/shapeless/nat.scala index 1ec83923a..c1a3e1031 100644 --- a/core/src/main/scala/shapeless/nat.scala +++ b/core/src/main/scala/shapeless/nat.scala @@ -61,4 +61,7 @@ object Nat extends Nats with NatScalaCompat { def toInt(n : Nat)(implicit toIntN : ToInt[n.N]) = toIntN() implicit def natOps[N <: Nat](n : N) : NatOps[N] = new NatOps(n) + + implicit def valueOfZero: ValueOf[_0] = new ValueOf(_0) + implicit def valueOfSucc[N <: Nat]: ValueOf[Succ[N]] = new ValueOf(Succ[N]()) } diff --git a/core/src/main/scala/shapeless/ops/coproduct.scala b/core/src/main/scala/shapeless/ops/coproduct.scala index d0d97a1cc..7b7a698a4 100644 --- a/core/src/main/scala/shapeless/ops/coproduct.scala +++ b/core/src/main/scala/shapeless/ops/coproduct.scala @@ -122,7 +122,7 @@ object coproduct { implicit def notMatched[C <: Coproduct, A, H, Next <: Nat]( implicit ev: A =:!= H, next: Aux[C, A, Next], - n: Witness.Aux[Succ[Next]] + n: ValueOf[Succ[Next]] ): Aux[H :+: C, A, Succ[Next]] = new IndexOf[H :+: C, A] { type Out = Succ[Next] def apply(): Out = n.value @@ -529,7 +529,7 @@ object coproduct { instance.asInstanceOf[Aux[HNil, CNil, CNil]] implicit def cconsZipWithKeys[KH, VH, KT <: HList, VT <: Coproduct]( - implicit wkh: Witness.Aux[KH], zipWithKeys: ZipWithKeys[KT, VT] + implicit wkh: ValueOf[KH], zipWithKeys: ZipWithKeys[KT, VT] ): Aux[KH :: KT, VH :+: VT, FieldType[KH, VH] :+: zipWithKeys.Out] = instance.asInstanceOf[Aux[KH :: KT, VH :+: VT, FieldType[KH, VH] :+: zipWithKeys.Out]] } @@ -567,7 +567,7 @@ object coproduct { type Aux[C <: Coproduct, N <: Nat, Out0 <: Coproduct] = Impl[C, N] {type Out = Out0} implicit def singleZipWithIndexImpl[CH, N <: Nat] - (implicit w: Witness.Aux[N]): Aux[CH :+: CNil, N, (CH, N) :+: CNil] = new Impl[CH :+: CNil, N] { + (implicit w: ValueOf[N]): Aux[CH :+: CNil, N, (CH, N) :+: CNil] = new Impl[CH :+: CNil, N] { type Out = (CH, N) :+: CNil def apply(c: CH :+: CNil): Out = Coproduct[Out]((c.head.get, w.value)) @@ -576,7 +576,7 @@ object coproduct { implicit def cpZipWithIndexImpl[CH, CT <: Coproduct, N <: Nat, OutC <: Coproduct] (implicit impl: Impl[CT, Succ[N]], - w: Witness.Aux[N] + w: ValueOf[N] ): Aux[CH :+: CT, N, (CH, N) :+: impl.Out] = new Impl[CH :+: CT, N] { type Out = (CH, N) :+: impl.Out @@ -637,7 +637,7 @@ object coproduct { } implicit def coproductLength[H, T <: Coproduct, N <: Nat] - (implicit lt: Aux[T, N], sn: Witness.Aux[Succ[N]]): Aux[H :+: T, Succ[N]] = new Length[H :+: T] { + (implicit lt: Aux[T, N], sn: ValueOf[Succ[N]]): Aux[H :+: T, Succ[N]] = new Length[H :+: T] { type Out = Succ[N] def apply(): Out = sn.value @@ -1257,7 +1257,7 @@ object coproduct { } implicit def coproductReify[H, T <: Coproduct](implicit - wh: Witness.Aux[H], + wh: ValueOf[H], rt: Reify[T] ): Aux[H :+: T, H :: rt.Out] = new Reify[H :+: T] { diff --git a/core/src/main/scala/shapeless/ops/hlists.scala b/core/src/main/scala/shapeless/ops/hlists.scala index e9a1167cf..1d4d87db8 100644 --- a/core/src/main/scala/shapeless/ops/hlists.scala +++ b/core/src/main/scala/shapeless/ops/hlists.scala @@ -298,7 +298,7 @@ object hlist { def apply(): Out = _0 } - implicit def hlistLength[H, T <: HList, N <: Nat](implicit lt : Aux[T, N], sn : Witness.Aux[Succ[N]]): Aux[H :: T, Succ[N]] = new Length[H :: T] { + implicit def hlistLength[H, T <: HList, N <: Nat](implicit lt : Aux[T, N], sn : ValueOf[Succ[N]]): Aux[H :: T, Succ[N]] = new Length[H :: T] { type Out = Succ[N] def apply(): Out = sn.value } @@ -2392,7 +2392,7 @@ object hlist { instance.asInstanceOf[Aux[HNil, HNil, HNil]] implicit def hconsZipWithKeys[KH, VH, KT <: HList, VT <: HList, KVT <: HList]( - implicit wkh: Witness.Aux[KH], zipWithKeys: ZipWithKeys.Aux[KT, VT, KVT] + implicit wkh: ValueOf[KH], zipWithKeys: ZipWithKeys.Aux[KT, VT, KVT] ): Aux[KH :: KT, VH :: VT, FieldType[KH, VH] :: KVT] = instance.asInstanceOf[Aux[KH :: KT, VH :: VT, FieldType[KH, VH] :: KVT]] } @@ -3013,7 +3013,7 @@ object hlist { } implicit def hlistReify[H, T <: HList, Out0 <: HList](implicit - wh: Witness.Aux[H], + wh: ValueOf[H], rt: Reify.Aux[T, Out0] ) : Aux[H :: T, H :: Out0] = new Reify[H :: T] { diff --git a/core/src/main/scala/shapeless/ops/maps.scala b/core/src/main/scala/shapeless/ops/maps.scala index 1563fefb3..7b59e99af 100644 --- a/core/src/main/scala/shapeless/ops/maps.scala +++ b/core/src/main/scala/shapeless/ops/maps.scala @@ -43,7 +43,7 @@ object maps { implicit def hlistFromMap[K0, V0, T <: HList] - (implicit wk: Witness.Aux[K0], tv: Typeable[V0], fmt: FromMap[T]): FromMap[FieldType[K0, V0] :: T] = + (implicit wk: ValueOf[K0], tv: Typeable[V0], fmt: FromMap[T]): FromMap[FieldType[K0, V0] :: T] = new FromMap[FieldType[K0, V0] :: T] { def apply[K, V](m: Map[K, V]): Option[FieldType[K0, V0] :: T] = { for { diff --git a/core/src/main/scala/shapeless/ops/nat.scala b/core/src/main/scala/shapeless/ops/nat.scala index cf1d82b8b..fab680770 100644 --- a/core/src/main/scala/shapeless/ops/nat.scala +++ b/core/src/main/scala/shapeless/ops/nat.scala @@ -269,7 +269,7 @@ object nat { } implicit def range2[A <: Nat, B <: Nat, L <: HList, LO <: HList](implicit - w: Witness.Aux[B], + w: ValueOf[B], r: Range.Aux[A, B, L], prep: Prepend.Aux[L, B :: HNil, LO] ): Aux[A, Succ[B], LO] = @@ -386,7 +386,7 @@ object nat { // nil ranges (both nil starting and recursive terminators) implicit def nilClosed[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : AuxF[Inclusive[A], Inclusive[A], A :: HNil] = new BoundedRange[Inclusive[A], Inclusive[A]] { type Out = A :: HNil @@ -395,7 +395,7 @@ object nat { } implicit def nilOpen[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : AuxF[Exclusive[A], Exclusive[A], HNil] = new BoundedRange[Exclusive[A], Exclusive[A]] { type Out = HNil @@ -404,7 +404,7 @@ object nat { } implicit def nilLeftOpenRightClosed[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : AuxF[Exclusive[A], Inclusive[A], A :: HNil] = new BoundedRange[Exclusive[A], Inclusive[A]] { type Out = A :: HNil @@ -413,7 +413,7 @@ object nat { } implicit def nilLeftClosedRightOpen[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : AuxF[Inclusive[A], Exclusive[A], A :: HNil] = new BoundedRange[Inclusive[A], Exclusive[A]] { type Out = A :: HNil @@ -433,7 +433,7 @@ object nat { } implicit def nilLeftClosedRightSoft[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : AuxF[Inclusive[A], SoftInclusive[A], A :: HNil] = new BoundedRange[Inclusive[A], SoftInclusive[A]] { type Out = A :: HNil @@ -446,7 +446,7 @@ object nat { implicit def leftOpenRightSoft[A <: Nat, B <: Nat, Sub <: HList] (implicit - w: Witness.Aux[Succ[B]], + w: ValueOf[Succ[B]], subRange: AuxF[Exclusive[A], SoftInclusive[B], Sub]) : AuxF[Exclusive[A], SoftInclusive[Succ[B]], Succ[B] :: Sub] = new BoundedRange[Exclusive[A], SoftInclusive[Succ[B]]] { @@ -457,7 +457,7 @@ object nat { implicit def leftClosedRightSoft[A <: Nat, B <: Nat, Sub <: HList] (implicit - w: Witness.Aux[Succ[B]], + w: ValueOf[Succ[B]], subRange: AuxF[Inclusive[A], SoftInclusive[B], Sub]) : AuxF[Inclusive[A], SoftInclusive[Succ[B]], Succ[B] :: Sub] = new BoundedRange[Inclusive[A], SoftInclusive[Succ[B]]] { @@ -471,7 +471,7 @@ object nat { implicit def closed[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList] (implicit - w: Witness.Aux[Succ[B]], + w: ValueOf[Succ[B]], subRange: AuxF[Inclusive[A], SoftInclusive[B], Sub], reverse: ReversePrepend.Aux[Sub, Succ[B] :: HNil, Rev]) : AuxF[Inclusive[A], Inclusive[Succ[B]], Rev] = @@ -494,7 +494,7 @@ object nat { implicit def leftOpenRightClosed[A <: Nat, B <: Nat, Sub <: HList, Rev <: HList] (implicit - w: Witness.Aux[Succ[B]], + w: ValueOf[Succ[B]], subRange: AuxF[Exclusive[A], SoftInclusive[B], Sub], reverse: ReversePrepend.Aux[Sub, Succ[B] :: HNil, Rev]) : AuxF[Exclusive[A], Inclusive[Succ[B]], Rev] = @@ -529,7 +529,7 @@ object nat { implicit def leftClosedRightOpenReverse[A <: Nat, B <: Nat, Sub <: HList] (implicit - wA: Witness.Aux[Succ[A]], + wA: ValueOf[Succ[A]], subRange: AuxF[Exclusive[B], SoftInclusive[A], Sub]) : AuxF[Inclusive[Succ[A]], Exclusive[B], Succ[A] :: Sub] = new BoundedRange[Inclusive[Succ[A]], Exclusive[B]] { @@ -549,7 +549,7 @@ object nat { implicit def closedReverse[A <: Nat, B <: Nat, Sub <: HList] (implicit - wA: Witness.Aux[Succ[A]], + wA: ValueOf[Succ[A]], subRange: AuxF[Inclusive[B], SoftInclusive[A], Sub]) : AuxF[Inclusive[Succ[A]], Inclusive[B], Succ[A] :: Sub] = new BoundedRange[Inclusive[Succ[A]], Inclusive[B]] { @@ -561,7 +561,7 @@ object nat { object Bound { implicit def inclusive[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : Inclusive[A] = new Inclusive[A] { type Out = A @@ -570,7 +570,7 @@ object nat { } implicit def exclusive[A <: Nat] - (implicit w: Witness.Aux[A]) + (implicit w: ValueOf[A]) : Exclusive[A] = new Exclusive[A] { type Out = A diff --git a/core/src/main/scala/shapeless/ops/records.scala b/core/src/main/scala/shapeless/ops/records.scala index fab7345c6..6678dbaa1 100644 --- a/core/src/main/scala/shapeless/ops/records.scala +++ b/core/src/main/scala/shapeless/ops/records.scala @@ -473,7 +473,7 @@ package record { } implicit def hlistKeys[K, V, T <: HList]( - implicit wk: Witness.Aux[K], kt: Keys[T] + implicit wk: ValueOf[K], kt: Keys[T] ): Aux[FieldType[K, V] :: T, K :: kt.Out] = new Keys[FieldType[K, V] :: T] { type Out = K :: kt.Out @@ -524,7 +524,7 @@ package record { def apply(): Out = HNil } - implicit def hlistSwapRecord[K, V, T <: HList](implicit wk: Witness.Aux[K], kt: SwapRecord[T]): Aux[FieldType[K, V] :: T, FieldType[V, K] :: kt.Out] = + implicit def hlistSwapRecord[K, V, T <: HList](implicit wk: ValueOf[K], kt: SwapRecord[T]): Aux[FieldType[K, V] :: T, FieldType[V, K] :: kt.Out] = new SwapRecord[FieldType[K, V] :: T] { type Out = FieldType[V, K] :: kt.Out def apply(): Out = field[V](wk.value) :: kt() @@ -552,7 +552,7 @@ package record { } implicit def hconsFields[K, V, T <: HList](implicit - key: Witness.Aux[K], + key: ValueOf[K], tailFields: Fields[T] ): Aux[FieldType[K, V] :: T, (K, V) :: tailFields.Out] = new Fields[FieldType[K, V] :: T] { @@ -589,7 +589,7 @@ package record { } implicit def hconsUnzipFields[K, V, T <: HList](implicit - key: Witness.Aux[K], + key: ValueOf[K], tailUF: UnzipFields[T] ): Aux[FieldType[K, V] :: T, K :: tailUF.Keys, V :: tailUF.Values] = new UnzipFields[FieldType[K, V] :: T] { @@ -628,7 +628,7 @@ package record { implicit def hnilToMapAnyNothing[L <: HNil]: Aux[L, Any, Nothing] = hnilToMap[Any, Nothing, L] implicit def hsingleToMap[K, V](implicit - wk: Witness.Aux[K] + wk: ValueOf[K] ): Aux[FieldType[K, V] :: HNil, K, V] = new ToMap[FieldType[K, V] :: HNil] { type Key = K @@ -640,7 +640,7 @@ package record { tailToMap: ToMap.Aux[TH :: TT, TK, TV], keyLub: Lub[HK, TK, K], valueLub: Lub[HV, TV, V], - wk: Witness.Aux[HK] + wk: ValueOf[HK] ): Aux[FieldType[HK, HV] :: TH :: TT, K, V] = new ToMap[FieldType[HK, HV] :: TH :: TT] { type Key = K diff --git a/core/src/main/scala/shapeless/ops/unions.scala b/core/src/main/scala/shapeless/ops/unions.scala index 8b4b33e8a..989b5166e 100644 --- a/core/src/main/scala/shapeless/ops/unions.scala +++ b/core/src/main/scala/shapeless/ops/unions.scala @@ -80,7 +80,7 @@ object union { def apply(): Out = HNil } - implicit def coproductKeys[K, V, T <: Coproduct](implicit wk: Witness.Aux[K], kt: Keys[T]): Aux[FieldType[K, V] :+: T, K :: kt.Out] = + implicit def coproductKeys[K, V, T <: Coproduct](implicit wk: ValueOf[K], kt: Keys[T]): Aux[FieldType[K, V] :+: T, K :: kt.Out] = new Keys[FieldType[K, V] :+: T] { type Out = K :: kt.Out def apply(): Out = wk.value :: kt() @@ -136,7 +136,7 @@ object union { } implicit def cconsFields[K, V, T <: Coproduct](implicit - key: Witness.Aux[K], + key: ValueOf[K], tailFields: Fields[T] ): Aux[FieldType[K, V] :+: T, (K, V) :+: tailFields.Out] = new Fields[FieldType[K, V] :+: T] { @@ -178,7 +178,7 @@ object union { } implicit def cconsUnzipFields[K, V, T <: Coproduct](implicit - key: Witness.Aux[K], + key: ValueOf[K], tailUF: UnzipFields[T] ): Aux[FieldType[K, V] :+: T, K :: tailUF.Keys, V :+: tailUF.Values] = new UnzipFields[FieldType[K, V] :+: T] { @@ -221,7 +221,7 @@ object union { implicit val cnilToMapAnyNothing: Aux[CNil, Any, Nothing] = cnilToMap[Any, Nothing] implicit def csingleToMap[K, V](implicit - wk: Witness.Aux[K] + wk: ValueOf[K] ): Aux[FieldType[K, V] :+: CNil, K, V] = new ToMap[FieldType[K, V] :+: CNil] { type Key = K @@ -235,7 +235,7 @@ object union { tailToMap: ToMap.Aux[TH :+: TT, TK, TV], keyLub: Lub[HK, TK, K], valueLub: Lub[HV, TV, V], - wk: Witness.Aux[HK] + wk: ValueOf[HK] ): Aux[FieldType[HK, HV] :+: TH :+: TT, K, V] = new ToMap[FieldType[HK, HV] :+: TH :+: TT] { type Key = K diff --git a/core/src/main/scala/shapeless/poly.scala b/core/src/main/scala/shapeless/poly.scala index 54c593adc..2ba7316b1 100644 --- a/core/src/main/scala/shapeless/poly.scala +++ b/core/src/main/scala/shapeless/poly.scala @@ -110,7 +110,7 @@ object PolyDefns extends Cases { implicit def bindFirstCase[BF, F, Head, Tail <: HList, Result0]( implicit unpack2: BF <:< BindFirst[F, Head], - witnessBF: Witness.Aux[BF], + witnessBF: ValueOf[BF], finalCall: Case.Aux[F, Head :: Tail, Result0] ): Case.Aux[BF, Tail, Result0] = new Case[BF, Tail] { type Result = Result0 @@ -133,7 +133,7 @@ object PolyDefns extends Cases { CurrentLength <: Nat ](implicit constraint: Self <:< Curried[F, ParameterAccumulator], - witnessSelf: Witness.Aux[Self], + witnessSelf: ValueOf[Self], finalCall: Case[F, AllParameters], length: ops.hlist.Length.Aux[CurrentParameter :: ParameterAccumulator, CurrentLength], reverseSplit: ops.hlist.ReverseSplit.Aux[AllParameters, CurrentLength, CurrentParameter :: ParameterAccumulator, RestParameters], @@ -148,7 +148,7 @@ object PolyDefns extends Cases { implicit def lastParameter[Self, F, LastParameter, ParameterAccumulator <: HList, AllParameters <: HList, Result0]( implicit constraint: Self <:< Curried[F, ParameterAccumulator], - witnessSelf: Witness.Aux[Self], + witnessSelf: ValueOf[Self], reverse: ops.hlist.Reverse.Aux[LastParameter :: ParameterAccumulator, AllParameters], finalCall: Case.Aux[F, AllParameters, Result0] ): Case1.Aux[Self, LastParameter, Result0] = Case1 { diff --git a/core/src/main/scala/shapeless/singletons.scala b/core/src/main/scala/shapeless/singletons.scala index d3d0a2324..299019617 100644 --- a/core/src/main/scala/shapeless/singletons.scala +++ b/core/src/main/scala/shapeless/singletons.scala @@ -16,77 +16,6 @@ package shapeless -/** Provides the value corresponding to a singleton type. - * - * See SIP-23 for a related proposed language change. - */ -trait Witness extends Serializable { - type T - val value: T {} -} - -object Witness { - type Aux[T0] = Witness { type T = T0 } - type Lt[Lub] = Witness { type T <: Lub } - - def mkWitness[A](v: A): Aux[A] = new Witness { - type T = A - val value = v - } - - implicit def of[T: ValueOf]: Witness.Aux[T] = - Witness.mkWitness(valueOf[T]) - - implicit def apply[T](t: T): Witness.Aux[t.type] = - Witness.mkWitness[t.type](t) - - implicit val witness0: Witness.Aux[_0] = - mkWitness(Nat._0) - - implicit def witnessN[P <: Nat]: Witness.Aux[Succ[P]] = - mkWitness(Succ[P]()) -} - -trait WitnessWith[TC[_]] extends Witness { - val instance: TC[T] -} - -object WitnessWith { - type Aux[TC[_], T0] = WitnessWith[TC] { type T = T0 } - type Lt[TC[_], Lub] = WitnessWith[TC] { type T <: Lub } - - implicit def apply[TC[_], T](t: T)(implicit tc: TC[t.type]): WitnessWith.Aux[TC, t.type] { val instance: tc.type } = - instance[TC, t.type](t, tc) - - def instance[TC[_], A](v: A, tc: TC[A]): WitnessWith.Aux[TC, A] { val instance: tc.type } = - new WitnessWith[TC] { - type T = A - val value: T = v - val instance: tc.type = tc - } -} - -trait NatWith[TC[_ <: Nat]] { - type N <: Nat - val instance: TC[N] -} - -object NatWith extends NatWithScalaCompat { - type Aux[TC[_ <: Nat], N0 <: Nat] = NatWith[TC] { type N = N0 } - - def depInstance[TC[_ <: Nat] <: AnyRef, N0 <: Nat](tc: TC[N0]): Aux[TC, N0] { val instance: tc.type } = - new NatWith[TC] { - type N = N0 - val instance: tc.type = tc - } - - def instance[TC[_ <: Nat], N0 <: Nat](tc: TC[N0]): Aux[TC, N0] = - new NatWith[TC] { - type N = N0 - val instance: TC[N] = tc - } -} - /** * Provides the widen type of a singleton type. * diff --git a/core/src/main/scala/shapeless/syntax/hlists.scala b/core/src/main/scala/shapeless/syntax/hlists.scala index aedeca462..be63aa23f 100644 --- a/core/src/main/scala/shapeless/syntax/hlists.scala +++ b/core/src/main/scala/shapeless/syntax/hlists.scala @@ -247,8 +247,8 @@ final class HListOps[L <: HList](l : L) extends Serializable { * * @author Andreas Koestler */ - def updateAtWith[V](n: NatWith[({ type λ[n <: Nat] = At[L, n]})#λ])(f: n.instance.Out => V) - (implicit upd: ModifierAt[L, n.N, n.instance.Out, V]): upd.Out = upd(l, f) + def updateAtWith[N <: Nat, V, AtOut](n: N)(f: AtOut => V) + (implicit at: At.Aux[L, N, AtOut], upd: ModifierAt[L, N, AtOut, V]): upd.Out = upd(l, f) class UpdatedTypeAux[U] { def apply[V, Out <: HList](v : V) diff --git a/core/src/main/scala/shapeless/syntax/records.scala b/core/src/main/scala/shapeless/syntax/records.scala index 3589cd54a..c3ab4d25f 100644 --- a/core/src/main/scala/shapeless/syntax/records.scala +++ b/core/src/main/scala/shapeless/syntax/records.scala @@ -30,51 +30,51 @@ final class RecordOps[L <: HList](val l : L) extends AnyVal with Serializable { /** * Returns the value associated with the singleton typed key k. Only available if this record has a field with - * with keyType equal to the singleton type k.T. + * with keyType equal to the singleton type K. */ - def get(k: Witness)(implicit selector : Selector[L, k.T]): selector.Out = selector(l) + def get[K <: Singleton](k: K)(implicit selector : Selector[L, K]): selector.Out = selector(l) /** * Returns the value associated with the singleton typed key k. Only available if this record has a field with - * with keyType equal to the singleton type k.T. + * with keyType equal to the singleton type K. * * Note that this can creates a bogus ambiguity with `HListOps#apply` as described in * https://issues.scala-lang.org/browse/SI-5142. If this method is accessible the conflict can be worked around by * using HListOps#at instead of `HListOps#apply`. */ - def apply(k: Witness)(implicit selector : Selector[L, k.T]): selector.Out = selector(l) + def apply[K <: Singleton](k: K)(implicit selector : Selector[L, K]): selector.Out = selector(l) /** * Returns the value associated with the singleton typed key k. Only available if this record has a field with - * with keyType equal to the singleton type k.T. + * with keyType equal to the singleton type K. */ - def fieldAt(k: Witness)(implicit selector : Selector[L, k.T]): FieldType[k.T, selector.Out] = field[k.T](selector(l)) + def fieldAt[K <: Singleton](k: K)(implicit selector : Selector[L, K]): FieldType[K, selector.Out] = field[K](selector(l)) /** * Updates or adds to this record a field with key k. The new field has a value of type V. Only available if this - * record has a field with keyType equal to the singleton type k.T. + * record has a field with keyType equal to the singleton type K. */ - def updated[V](k: Witness, v: V)(implicit updater: Updater[L, FieldType[k.T, V]]) : updater.Out = updater(l, field[k.T](v)) + def updated[K <: Singleton, V](k: K, v: V)(implicit updater: Updater[L, FieldType[K, V]]) : updater.Out = updater(l, field[K](v)) /** * Replaces the value of field k with a value of the same type. Only available if this record has a field with - * keyType equal to the singleton type k.T and valueType equal to V. + * keyType equal to the singleton type K and valueType equal to V. */ - def replace[V](k: Witness, v: V) - (implicit ev: Selector.Aux[L, k.T, V], updater: Updater[L, FieldType[k.T, V]]): updater.Out = updater(l, field[k.T](v)) + def replace[K <: Singleton, V](k: K, v: V) + (implicit ev: Selector.Aux[L, K, V], updater: Updater[L, FieldType[K, V]]): updater.Out = updater(l, field[K](v)) /** * Updates a field having a value with type A by given function. */ - def updateWith[W](k: WitnessWith[FSL])(f: k.instance.Out => W) - (implicit modifier: Modifier[L, k.T, k.instance.Out, W]): modifier.Out = modifier(l, f) - type FSL[K] = Selector[L, K] + def updateWith[K <: Singleton, W, FSLOut](k: K)(f: FSLOut => W) + (implicit fsl: FSL[K, FSLOut], modifier: Modifier[L, K, FSLOut, W]): modifier.Out = modifier(l, f) + type FSL[K, Out] = Selector.Aux[L, K, Out] /** * Remove the field associated with the singleton typed key k, returning both the corresponding value and the updated - * record. Only available if this record has a field with keyType equal to the singleton type k.T. + * record. Only available if this record has a field with keyType equal to the singleton type K. */ - def remove(k : Witness)(implicit remover: Remover[L, k.T]): remover.Out = remover(l) + def remove[K](k: ValueOf[K])(implicit remover: Remover[L, K]): remover.Out = remover(l) /** * Updates or adds to this record a field of type F. @@ -83,9 +83,9 @@ final class RecordOps[L <: HList](val l : L) extends AnyVal with Serializable { /** * Remove the field associated with the singleton typed key k, returning the updated record. Only available if this - * record has a field with keyType equal to the singleton type k.T. + * record has a field with keyType equal to the singleton type K. */ - def -[V, Out <: HList](k: Witness)(implicit remover : Remover.Aux[L, k.T, (V, Out)]): Out = remover(l)._2 + def -[K <: Singleton, V, Out <: HList](k: K)(implicit remover : Remover.Aux[L, K, (V, Out)]): Out = remover(l)._2 /** * Returns the union of this record and another record. @@ -111,9 +111,9 @@ final class RecordOps[L <: HList](val l : L) extends AnyVal with Serializable { /** * Rename the field associated with the singleton typed key oldKey. Only available if this - * record has a field with keyType equal to the singleton type oldKey.T. + * record has a field with keyType equal to the singleton type Old. */ - def renameField(oldKey: Witness, newKey: Witness)(implicit renamer: Renamer[L, oldKey.T, newKey.T]): renamer.Out = renamer(l) + def renameField[Old <: Singleton, New <: Singleton](oldKey: Old, newKey: New)(implicit renamer: Renamer[L, Old, New]): renamer.Out = renamer(l) /** * Returns the keys of this record as an `HList` of singleton typed values. diff --git a/core/src/main/scala/shapeless/syntax/singletons.scala b/core/src/main/scala/shapeless/syntax/singletons.scala index b3743bc53..68980a8b0 100644 --- a/core/src/main/scala/shapeless/syntax/singletons.scala +++ b/core/src/main/scala/shapeless/syntax/singletons.scala @@ -23,14 +23,14 @@ trait SingletonOps { type T /** - * Returns a Witness of the singleton type of this value. + * Returns a value of the singleton type of this value. */ - val witness: Witness.Aux[T] + val value: T /** * Narrows this value to its singleton type. */ - def narrow: T {} = witness.value + def narrow: T {} = value /** * Returns the provided value tagged with the singleton type of this value as its key in a record-like structure. @@ -41,14 +41,14 @@ trait SingletonOps { object SingletonOps { type Aux[A] = SingletonOps { type T = A } - def instance[A](w: Witness.Aux[A]): Aux[A] = + def instance[A <: Singleton](w: A): Aux[A] = new SingletonOps { type T = A - val witness = w + val value = w } } object singleton { - implicit def mkSingletonOps[T](t: T): SingletonOps.Aux[t.type] = - SingletonOps.instance[t.type](Witness(t)) + implicit def mkSingletonOps[T <: Singleton](t: T): SingletonOps.Aux[t.type] = + SingletonOps.instance[t.type](t) } diff --git a/core/src/main/scala/shapeless/syntax/std/tuples.scala b/core/src/main/scala/shapeless/syntax/std/tuples.scala index 3a53c6cab..5d45cd71e 100644 --- a/core/src/main/scala/shapeless/syntax/std/tuples.scala +++ b/core/src/main/scala/shapeless/syntax/std/tuples.scala @@ -197,8 +197,8 @@ final class TupleOps[T](t: T) extends Serializable { * * @author Andreas Koestler */ - def updateAtWith[U](n: NatWith[({ type λ[t <: Nat] = At[T, t] })#λ])(f: n.instance.Out => U) - (implicit upd: ModifierAt[T, n.N, n.instance.Out, U]): upd.Out = upd(t, f) + def updateAtWith[N <: Nat, U, AtOut](n: N)(f: AtOut => U) + (implicit at: At.Aux[T, N, AtOut], upd: ModifierAt[T, N, AtOut, U]): upd.Out = upd(t, f) class UpdatedAtAux[N <: Nat] { def apply[U, V, R](u: U)(implicit replacer: ReplaceAt.Aux[T, N, U, (V, R)]): R = replacer(t, u)._2 diff --git a/core/src/main/scala/shapeless/syntax/unions.scala b/core/src/main/scala/shapeless/syntax/unions.scala index 4c49fc444..10c734968 100644 --- a/core/src/main/scala/shapeless/syntax/unions.scala +++ b/core/src/main/scala/shapeless/syntax/unions.scala @@ -31,7 +31,7 @@ final class UnionOps[C <: Coproduct](val c : C) extends AnyVal with Serializable * Returns the value associated with the singleton typed key k. Only available if this union has a field with * with keyType equal to the singleton type k.T. */ - def get(k: Witness)(implicit selector : Selector[C, k.T]): selector.Out = selector(c) + def get[K <: Singleton](k: K)(implicit selector : Selector[C, K]): selector.Out = selector(c) /** * Returns the value associated with the singleton typed key k. Only available if this union has a field with @@ -41,7 +41,7 @@ final class UnionOps[C <: Coproduct](val c : C) extends AnyVal with Serializable * https://issues.scala-lang.org/browse/SI-5142. If this method is accessible the conflict can be worked around by * using CoproductOps#at instead of `CoproductOps#apply`. */ - def apply(k: Witness)(implicit selector : Selector[C, k.T]): selector.Out = selector(c) + def apply[K <: Singleton](k: K)(implicit selector : Selector[C, K]): selector.Out = selector(c) /** * Returns the keys of this union as an `HList` of singleton typed values. diff --git a/core/src/main/scala/shapeless/typeclass.scala b/core/src/main/scala/shapeless/typeclass.scala index 0cf3ed28a..6cbaec959 100644 --- a/core/src/main/scala/shapeless/typeclass.scala +++ b/core/src/main/scala/shapeless/typeclass.scala @@ -107,7 +107,7 @@ trait LabelledProductTypeClassCompanion[C[_]] extends Serializable { new Instance(typeClass.emptyProduct) implicit def deriveHCons[HK <: String, HV, TKV <: HList, TV <: HList]( - implicit key: Witness.Aux[HK], ch: => C[HV], ct: Wrap.Aux[TKV, TV] + implicit key: ValueOf[HK], ch: => C[HV], ct: Wrap.Aux[TKV, TV] ): Wrap.Aux[FieldType[HK, HV] :: TKV, HV :: TV] = new Instance[FieldType[HK, HV] :: TKV, HV :: TV]( typeClass.product(key.value, ch, ct.unwrap) @@ -174,7 +174,7 @@ trait LabelledTypeClassCompanion[C[_]] extends LabelledProductTypeClassCompanion new Instance(typeClass.emptyCoproduct) implicit def deriveCCons[HK <: String, HV, TKV <: Coproduct, TV <: Coproduct]( - implicit key: Witness.Aux[HK], ch: => C[HV], ct: Wrap.Aux[TKV, TV] + implicit key: ValueOf[HK], ch: => C[HV], ct: Wrap.Aux[TKV, TV] ): Wrap.Aux[FieldType[HK, HV] :+: TKV, HV :+: TV] = new Instance[FieldType[HK, HV] :+: TKV, HV :+: TV]( typeClass.coproduct(key.value, ch, ct.unwrap) diff --git a/core/src/test/scala/shapeless/generic.scala b/core/src/test/scala/shapeless/generic.scala index 7ef50372e..a497e7c56 100644 --- a/core/src/test/scala/shapeless/generic.scala +++ b/core/src/test/scala/shapeless/generic.scala @@ -340,7 +340,7 @@ class GenericTests { val c1 = gen.from(c0) typed[Enum](c1) - val abc = ops.coproduct.LiftAll[Witness.Aux, gen.Repr] + val abc = ops.coproduct.LiftAll[ValueOf, gen.Repr] assertEquals(List(A, B, C), abc.instances.toList.map(_.value)) } @@ -1251,7 +1251,7 @@ package TestPrefixes1 { } package TestSingletonMembers { - case class CC(i: Int, s: Witness.`"msg"`.T) + case class CC(i: Int, s: "msg") object Derivations2 { Generic[CC] diff --git a/core/src/test/scala/shapeless/generic1.scala b/core/src/test/scala/shapeless/generic1.scala index 269a7678e..0bbf703a0 100644 --- a/core/src/test/scala/shapeless/generic1.scala +++ b/core/src/test/scala/shapeless/generic1.scala @@ -152,13 +152,13 @@ package Generic1TestsAux { } // Pointed can be built for Singleton types - implicit def constSingletonPointed[T](implicit w: Witness.Aux[T]): Pointed[Const[T]#λ] = + implicit def constSingletonPointed[T](implicit w: ValueOf[T]): Pointed[Const[T]#λ] = new Pointed[Const[T]#λ] { def point[A](a: A): T = w.value } implicit def isCPointedSingleSingleton[C]( - implicit w: Witness.Aux[C], pf: => Pointed[Const[C]#λ] + implicit w: ValueOf[C], pf: => Pointed[Const[C]#λ] ): Pointed[({type λ[A] = Const[C]#λ[A] :+: Const[CNil]#λ[A] })#λ] = new Pointed[({type λ[A] = Const[C]#λ[A] :+: Const[CNil]#λ[A] })#λ] { def point[A](a: A): Const[C]#λ[A] :+: Const[CNil]#λ[A] = Inl(pf.point(a)) diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 674be262a..34318a315 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -3125,23 +3125,23 @@ class HListTests { object Obj val l = SFoo(23, "foo", "bar", Obj, true) - typed[Witness.`23`.T :: Witness.`"foo"`.T :: Witness.`"bar"`.T :: Obj.type :: Witness.`true`.T :: HNil](l) + typed[23 :: "foo" :: "bar" :: Obj.type :: true :: HNil](l) // Annotations on the LHS here and subsequently, otherwise scalac will // widen the RHS to a non-singleton type. - val v1: Witness.`23`.T = l.head + val v1: 23 = l.head assertEquals(23, v1) - val v2: Witness.`"foo"`.T = l.tail.head + val v2: "foo" = l.tail.head assertEquals("foo", v2) - val v3: Witness.`"bar"`.T = l.tail.tail.head + val v3: "bar" = l.tail.tail.head assertEquals("bar", v3) val v4: Obj.type = l.tail.tail.tail.head assertEquals(Obj, v4) - val v5: Witness.`true`.T = l.tail.tail.tail.tail.head + val v5: true = l.tail.tail.tail.tail.head assertEquals(true, v5) val v6 = l.tail.tail.tail.tail.tail diff --git a/core/src/test/scala/shapeless/implicits.scala b/core/src/test/scala/shapeless/implicits.scala index f11fbb476..7bc211b97 100644 --- a/core/src/test/scala/shapeless/implicits.scala +++ b/core/src/test/scala/shapeless/implicits.scala @@ -182,8 +182,8 @@ class CachedTest { val h: Int = gen.to(q).head val th: String = gen.to(q).tail.head - val lh: FieldType[Witness.`"i"`.T, Int] = lgen.to(q).head - val lth: FieldType[Witness.`"s"`.T, String] = lgen.to(q).tail.head + val lh: FieldType["i", Int] = lgen.to(q).head + val lth: FieldType["s", String] = lgen.to(q).tail.head } @Test diff --git a/core/src/test/scala/shapeless/labelledgeneric.scala b/core/src/test/scala/shapeless/labelledgeneric.scala index e8ec6925c..50f87ae73 100644 --- a/core/src/test/scala/shapeless/labelledgeneric.scala +++ b/core/src/test/scala/shapeless/labelledgeneric.scala @@ -112,7 +112,7 @@ object ScalazTaggedAux { implicit val hnilTC: TC[HNil] = instance("HNil") implicit def hconsTC[K <: String, H, T <: HList]( - implicit key: Witness.Aux[K], headTC: => TC[H], tailTC: TC[T] + implicit key: ValueOf[K], headTC: => TC[H], tailTC: TC[T] ): TC[FieldType[K, H] :: T] = instance { s"${key.value}: ${headTC()} :: ${tailTC()}" } @@ -130,7 +130,7 @@ object ScalazTaggedAux { // FIXME: Workaround #309 implicit def hconsTCTagged[K <: String, H, HT, T <: HList]( - implicit key: Witness.Aux[K], headTC: => TC[H @@ HT], tailTC: TC[T] + implicit key: ValueOf[K], headTC: => TC[H @@ HT], tailTC: TC[T] ): TC[FieldType[K, H @@ HT] :: T] = instance { s"${key.value}: ${headTC()} :: ${tailTC()}" } diff --git a/core/src/test/scala/shapeless/lenses.scala b/core/src/test/scala/shapeless/lenses.scala index 8f4327494..760e4dc6f 100644 --- a/core/src/test/scala/shapeless/lenses.scala +++ b/core/src/test/scala/shapeless/lenses.scala @@ -210,8 +210,7 @@ trait LensTests { def testRecords: Unit = { import labelled.FieldType, syntax.singleton._ - val (fooT, barT) = (Witness("foo"), Witness("bar")) - type LT = (fooT.T FieldType Int) :: (barT.T FieldType String) :: HNil + type LT = ("foo" FieldType Int) :: ("bar" FieldType String) :: HNil val l = ("foo" ->> 42) :: ("bar" ->> "hi") :: HNil typed[LT](l) diff --git a/core/src/test/scala/shapeless/records.scala b/core/src/test/scala/shapeless/records.scala index 6e83dcdaf..89527f44e 100644 --- a/core/src/test/scala/shapeless/records.scala +++ b/core/src/test/scala/shapeless/records.scala @@ -464,10 +464,10 @@ class RecordTests { assertEquals((intField1 ->> 23) :: (stringField1 ->> "foo") :: (boolField1 ->> true) :: (doubleField1 ->> 2.0) :: HNil, r3) } - val wIntField1 = Witness("intField1") - val wStringField1 = Witness("stringField1") - val wBoolField1 = Witness("boolField1") - val wDoubleField1 = Witness("doubleField1") + type wIntField1 = "intField1" + type wStringField1 = "stringField1" + type wBoolField1 = "boolField1" + type wDoubleField1 = "doubleField1" @Test def testAppendLiteral: Unit = { @@ -477,11 +477,11 @@ class RecordTests { HNil val r2 = r1 + ("boolField1" ->> true) - typed[FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: HNil](r2) + typed[FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: HNil](r2) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("boolField1" ->> true) :: HNil, r2) val r3 = r2 + ("doubleField1" ->> 2.0) - typed[FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: FieldType[wDoubleField1.T, Double] :: HNil](r3) + typed[FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: FieldType[wDoubleField1, Double] :: HNil](r3) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("boolField1" ->> true) :: ("doubleField1" ->> 2.0) :: HNil, r3) } @@ -541,39 +541,39 @@ class RecordTests { HNil val rm1 = r1.remove("intField1") - typed[(Int, FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: FieldType[wDoubleField1.T, Double] :: HNil)](rm1) + typed[(Int, FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: FieldType[wDoubleField1, Double] :: HNil)](rm1) assertEquals(23, rm1._1) assertEquals(("stringField1" ->> "foo") :: ("boolField1" ->> true) :: ("doubleField1" ->> 2.0) :: HNil, rm1._2) val rm2 = r1.remove("stringField1") - typed[(String, FieldType[wIntField1.T, Int] :: FieldType[wBoolField1.T, Boolean] :: FieldType[wDoubleField1.T, Double] :: HNil)](rm2) + typed[(String, FieldType[wIntField1, Int] :: FieldType[wBoolField1, Boolean] :: FieldType[wDoubleField1, Double] :: HNil)](rm2) assertEquals("foo", rm2._1) assertEquals(("intField1" ->> 23) :: ("boolField1" ->> true) :: ("doubleField1" ->> 2.0) :: HNil, rm2._2) val rm3 = r1.remove("boolField1") - typed[(Boolean, FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wDoubleField1.T, Double] :: HNil)](rm3) + typed[(Boolean, FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wDoubleField1, Double] :: HNil)](rm3) assertEquals(true, rm3._1) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("doubleField1" ->> 2.0) :: HNil, rm3._2) val rm4 = r1.remove("doubleField1") - typed[(Double, FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: HNil)](rm4) + typed[(Double, FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: HNil)](rm4) assertEquals(2.0, rm4._1, Double.MinPositiveValue) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("boolField1" ->> true) :: HNil, rm4._2) val r2 = r1 - "intField1" - typed[FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: FieldType[wDoubleField1.T, Double] :: HNil](r2) + typed[FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: FieldType[wDoubleField1, Double] :: HNil](r2) assertEquals(("stringField1" ->> "foo") :: ("boolField1" ->> true) :: ("doubleField1" ->> 2.0) :: HNil, r2) val r3 = r1 - "stringField1" - typed[FieldType[wIntField1.T, Int] :: FieldType[wBoolField1.T, Boolean] :: FieldType[wDoubleField1.T, Double] :: HNil](r3) + typed[FieldType[wIntField1, Int] :: FieldType[wBoolField1, Boolean] :: FieldType[wDoubleField1, Double] :: HNil](r3) assertEquals(("intField1" ->> 23) :: ("boolField1" ->> true) :: ("doubleField1" ->> 2.0) :: HNil, r3) val r4 = r1 - "boolField1" - typed[FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wDoubleField1.T, Double] :: HNil](r4) + typed[FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wDoubleField1, Double] :: HNil](r4) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("doubleField1" ->> 2.0) :: HNil, r4) val r5 = r1 - "doubleField1" - typed[FieldType[wIntField1.T, Int] :: FieldType[wStringField1.T, String] :: FieldType[wBoolField1.T, Boolean] :: HNil](r5) + typed[FieldType[wIntField1, Int] :: FieldType[wStringField1, String] :: FieldType[wBoolField1, Boolean] :: HNil](r5) assertEquals(("intField1" ->> 23) :: ("stringField1" ->> "foo") :: ("boolField1" ->> true) :: HNil, r5) } @@ -591,7 +591,7 @@ class RecordTests { @Test def testLacksKey: Unit = { - def without[R <: HList, O <: HList](k: Witness)(r: R)(f: R => O)(implicit ev: LacksKey[R, k.T]): O = f(r) + def without[R <: HList, O <: HList, K <: Singleton](k: K)(r: R)(f: R => O)(implicit ev: LacksKey[R, K]): O = f(r) type R1 = Record.`"a" -> Int, "b" -> String, "c" -> Boolean`.T type R2 = Record.`"c" -> Boolean, "a" -> Int, "b" -> String`.T @@ -1103,12 +1103,9 @@ class RecordTests { def testSwapRecord: Unit = { import shapeless.ops.record.SwapRecord - val rt = Record.`"x" -> Int, "y" -> String, "z" -> Boolean` - type TestRecord = rt.T + type TestRecord = "x" ->> Int :: "y" ->> String :: "z" -> Boolean :: HNil - val (x, y, z) = (Witness("x"), Witness("y"), Witness("z")) - - val fields: (FieldType[Int, x.T] :: FieldType[String, y.T] :: FieldType[Boolean, z.T] :: HNil) = SwapRecord[TestRecord].apply() + val fields: (FieldType[Int, "x"] :: FieldType[String, "y"] :: FieldType[Boolean, "z"] :: HNil) = SwapRecord[TestRecord].apply() assertEquals(fields.toList, List("x", "y", "z")) } @@ -1137,7 +1134,7 @@ class RecordTests { val tagged = tag[Int]("42") val head1 = "k" ->> tagged - val head2 = field[Witness.`"k"`.T](tagged) + val head2 = field["k"](tagged) val rec1 = head1 :: HNil val rec2 = head2 :: HNil @@ -1165,7 +1162,7 @@ class RecordTests { val select = Selector[swap.Out, Int] val swapped = swap() - assertTypedEquals[Witness.`"a"`.T](swapped.head, select(swapped)) + assertTypedEquals["a"](swapped.head, select(swapped)) } @Test diff --git a/core/src/test/scala/shapeless/singletons.scala b/core/src/test/scala/shapeless/singletons.scala index 1173692ce..60b14e399 100644 --- a/core/src/test/scala/shapeless/singletons.scala +++ b/core/src/test/scala/shapeless/singletons.scala @@ -31,24 +31,16 @@ class SingletonTypesTests { import SingletonTypeTestsDefns._ import syntax.singleton._ - val wTrue = Witness(true) - type True = wTrue.T - val wFalse = Witness(false) - type False = wFalse.T - - val w0 = Witness(0) - type _0 = w0.T - val w1 = Witness(1) - type _1 = w1.T - val w2 = Witness(2) - type _2 = w2.T - val w3 = Witness(3) - type _3 = w3.T - - val wFoo = Witness("foo") - type Foo = wFoo.T - val wBar = Witness("bar") - type Bar = wBar.T + type True = true + type False = false + + type _0 = 0 + type _1 = 1 + type _2 = 2 + type _3 = 3 + + type Foo = "foo" + type Bar = "bar" @Test def testRefine: Unit = { @@ -135,15 +127,15 @@ class SingletonTypesTests { } object LiteralShow { - implicit val showTrue = new LiteralShow[Witness.`true`.T] { def show = "true" } - implicit val showFalse = new LiteralShow[Witness.`false`.T] { def show = "false" } + implicit val showTrue = new LiteralShow[true] { def show = "true" } + implicit val showFalse = new LiteralShow[false] { def show = "false" } - implicit val showOne = new LiteralShow[Witness.`1`.T] { def show = "One" } - implicit val showTwo = new LiteralShow[Witness.`2`.T] { def show = "Two" } - implicit val showThree = new LiteralShow[Witness.`3`.T] { def show = "Three" } + implicit val showOne = new LiteralShow[1] { def show = "One" } + implicit val showTwo = new LiteralShow[2] { def show = "Two" } + implicit val showThree = new LiteralShow[3] { def show = "Three" } - implicit val showFoo = new LiteralShow[Witness.`"foo"`.T] { def show = "'foo" } - implicit val showBar = new LiteralShow[Witness.`"bar"`.T] { def show = "'bar" } + implicit val showFoo = new LiteralShow["foo"] { def show = "'foo" } + implicit val showBar = new LiteralShow["bar"] { def show = "'bar" } } def literalShow[T](t: T)(implicit s: LiteralShow[T]) = s.show @@ -206,96 +198,7 @@ class SingletonTypesTests { assertEquals("'foo, 'bar", sFooBar) } - @Test - def testWitness: Unit = { - val wTrue = Witness(true) - val wFalse = Witness(false) - - sameTyped(wTrue)(wTrue) - illTyped("sameTyped(wTrue)(wFalse)") - - val w13 = Witness(13) - val w23 = Witness(23) - - sameTyped(w13)(w13) - illTyped("sameTyped(w13)(w23)") - - val wFoo = Witness("foo") - val wBar = Witness("bar") - - sameTyped(wFoo)(wFoo) - illTyped("sameTyped(wFoo)(wBar)") - } - - def convert(w: Witness): Witness.Aux[w.T] = w - - def boundedConvert2[B](w: Witness.Lt[B]): Witness.Aux[w.T] = w - - def testSingletonWitness: Unit = { - trait Bound - object Foo extends Bound - val bar = "bar" - val wFoo = Witness(Foo) - val wBar = Witness(bar) - - typed[Foo.type](wFoo.value) - typed[bar.type](wBar.value) - - val cFoo = convert(Foo) - val cBar = convert(bar) - - sameTyped(cFoo)(Witness(Foo)) - sameTyped(cBar)(Witness(bar)) - - val bcFoo = boundedConvert2[Bound](Foo) - val bcBar = boundedConvert2[String](bar) - - sameTyped(bcFoo)(Witness(Foo)) - sameTyped(bcBar)(Witness(bar)) - } - - @Test - def testWitnessConversion: Unit = { - val cTrue = convert(true) - val cFalse = convert(false) - - sameTyped(cTrue)(Witness(true)) - sameTyped(cFalse)(Witness(false)) - - illTyped("sameTyped(cTrue)(Witness(false))") - illTyped("sameTyped(cFalse)(Witness(true))") - - val c13 = convert(13) - val c23 = convert(23) - - sameTyped(c13)(Witness(13)) - sameTyped(c23)(Witness(23)) - - illTyped("sameTyped(c13)(Witness(23))") - illTyped("sameTyped(c23)(Witness(13))") - - val cFoo = convert("foo") - val cBar = convert("bar") - - sameTyped(cFoo)(Witness("foo")) - sameTyped(cBar)(Witness("bar")) - - illTyped("""sameTyped(cFoo)(Witness("bar"))""") - illTyped("""sameTyped(cBar)(Witness("foo"))""") - } - - def boundedConvert(w: Witness.Lt[Int]): Witness.Aux[w.T] = w - - @Test - def testBoundedWitnessConversion: Unit = { - val c13 = boundedConvert(13) - sameTyped(c13)(Witness(13)) - illTyped("sameTyped(c13)(Witness(23))") - illTyped("boundedConvert(true)") - illTyped("""boundedConvert("foo")""") - } - - def showLiteral(t: Witness)(implicit s: Show[t.T]) = s.show + def showLiteral[K <: Singleton](t: K)(implicit s: Show[K]) = s.show @Test def testLiteralTypeClass: Unit = { @@ -323,130 +226,34 @@ class SingletonTypesTests { illTyped("showLiteral(0)") } - trait ShowWitness[T] { - def show: String - } - - object ShowWitness { - implicit def showWitness[T](implicit w: Witness.Aux[T]) = - new ShowWitness[T] { - def show = w.value.toString - } - } - - def showWitness(w: Witness)(implicit s: ShowWitness[w.T]) = s.show - - @Test - def testWitnessTypeClass: Unit = { - val sTrue = showWitness(true) - assertEquals("true", sTrue) - - val sFalse = showWitness(false) - assertEquals("false", sFalse) - - val sOne = showWitness(1) - assertEquals("1", sOne) - - val sTwo = showWitness(2) - assertEquals("2", sTwo) - - val sThree = showWitness(3) - assertEquals("3", sThree) - - val sFooSym = showWitness("foo") - assertEquals("foo", sFooSym) - - val sBarSym = showWitness("bar") - assertEquals("bar", sBarSym) - } - - def showWitnessWith(w: WitnessWith[Show]) = w.instance.show - - @Test - def testWitnessWith: Unit = { - val sTrue = showWitnessWith(true) - assertEquals("true", sTrue) - - val sFalse = showWitnessWith(false) - assertEquals("false", sFalse) - - val sOne = showWitnessWith(1) - assertEquals("One", sOne) - - val sTwo = showWitnessWith(2) - assertEquals("Two", sTwo) - - val sThree = showWitnessWith(3) - assertEquals("Three", sThree) - - val sFooSym = showWitnessWith("foo") - assertEquals("'foo", sFooSym) - - val sBarSym = showWitnessWith("bar") - assertEquals("'bar", sBarSym) - } - - trait Rel[T] { - type Out - } - - object Rel { - implicit def relTrue: Rel[True] { type Out = Int } = new Rel[True] { type Out = Int } - implicit def relFalse: Rel[False] { type Out = String } = new Rel[False] { type Out = String } - } - - def check(w: WitnessWith[Rel])(v: w.instance.Out) = v - - @Test - def testWitnessWithOut: Unit = { - val relTrue = check(true)(23) - typed[Int](relTrue) - - val relFalse = check(false)("foo") - typed[String](relFalse) - - illTyped("""check(true)("foo")""") - illTyped("check(false)(23)") - illTyped("check(23)(23)") - } - - @Test - def testValueClass: Unit = { - val x = new ValueTest(5) - val y = new ValueTest(5) - val wX = Witness(x) - val wY = Witness(y) - illTyped("implicitly[wX.T =:= wY.T]", "Cannot prove that wX.T =:= wY.T.") - } - @Test def primitiveWiden: Unit = { { - val w = Widen[Witness.`2`.T] + val w = Widen[2] illTyped("w(3)", "type mismatch;.*") val n = w(2) val n0: Int = n - illTyped("val n1: Witness.`2`.T = n", "type mismatch;.*") + illTyped("val n1: 2 = n", "type mismatch;.*") assertTypedEquals[Int](2, n) } { - val w = Widen[Witness.`true`.T] + val w = Widen[true] illTyped("w(false)", "type mismatch;.*") val b = w(true) val b0: Boolean = b - illTyped("val b1: Witness.`true`.T = b", "type mismatch;.*") + illTyped("val b1: true = b", "type mismatch;.*") assertTypedEquals[Boolean](true, b) } { - val w = Widen[Witness.`"ab"`.T] + val w = Widen["ab"] illTyped("""w("s")""", "type mismatch;.*") val s = w("ab") val s0: String = s - illTyped("""val s1: Witness.`"ab"`.T = s""", "type mismatch;.*") + illTyped("""val s1: "ab" = s""", "type mismatch;.*") assertTypedEquals[String]("ab", s) } @@ -458,23 +265,23 @@ class SingletonTypesTests { // Having it in scope makes the illTyped tests fail in an unexpected way. def narrowSymbol = ??? - val w = Widen[Witness.`"ab"`.T] + val w = Widen["ab"] illTyped("""w("s".narrow)""", "type mismatch;.*") val s = w("ab".narrow) val s0: String = s - illTyped("""val s1: Witness.`"ab"`.T = s""", "type mismatch;.*") + illTyped("""val s1: "ab" = s""", "type mismatch;.*") assertTypedEquals[String]("ab", s) } @Test def aliasWiden: Unit = { - type T = Witness.`2`.T + type T = 2 val w = Widen[T] illTyped("w(3)", "type mismatch;.*") val n = w(2) val n0: Int = n - illTyped("val n1: Witness.`2`.T = n", "type mismatch;.*") + illTyped("val n1: 2 = n", "type mismatch;.*") assertTypedEquals[Int](2, n) } @@ -508,7 +315,7 @@ class SingletonTypesTests { def testWitnessTypeRefType: Unit = { trait B1 { type T <: B - def getT(implicit w: Witness.Aux[T]): T = w.value + def getT(implicit w: ValueOf[T]): T = w.value } case class A1() extends B1 { @@ -522,10 +329,7 @@ class SingletonTypesTests { val o: AnyRef = new Object {} val wO = { - final class W extends _root_.shapeless.Witness { - type T = o.type - val value: T = o - } + final class W extends ValueOf[o.type](o) new W } diff --git a/core/src/test/scala/shapeless/typeable.scala b/core/src/test/scala/shapeless/typeable.scala index 4605939aa..2b614b213 100644 --- a/core/src/test/scala/shapeless/typeable.scala +++ b/core/src/test/scala/shapeless/typeable.scala @@ -488,17 +488,10 @@ class TypeableTests { @Test def testSingletons: Unit = { - val wOne = Witness(1) - type One = wOne.T - - val wTrue = Witness(true) - type True = wTrue.T - - val wFoo = Witness("foo") - type Foo = wFoo.T - - val wSym = Witness("Foo") - type Sym = wSym.T + type One = 1 + type True = true + type Foo = "foo" + type Sym = "Foo" object ObjA object ObjB @@ -599,14 +592,11 @@ class TypeableTests { val cpd: CP = Coproduct[CP](2.0) assertEquals("Typeable[Double :+: Boolean :+: CNil]", typeableString(cpd)) - val wOne = Witness(1) - type One = wOne.T + type One = 1 val one: One = 1 assertEquals("Typeable[Int(1)]", typeableString(one)) - object FooBar - val wFB = Witness(FooBar) - type FooBarT = wFB.T + type FooBarT = FooBar.type val foobar: FooBarT = FooBar assertEquals("Typeable[FooBar.type]", typeableString(foobar)) @@ -685,7 +675,6 @@ class TypeableTests { object *** final case class <+>[A](left: A, right: A) val |+| = "Tie-fighter" - val witness = Witness("witness") // `Typeable.genTraversableTypeable` is not a macro. // Appart from that there is a difference in the encoded name between JVM and JS. @@ -694,7 +683,7 @@ class TypeableTests { assertEquals("***.type", Typeable[***.type].describe) assertEquals("<+>[String,String]", Typeable[<+>[String]].describe) assertEquals("|+|.type", Typeable[|+|.type].describe) - assertEquals("String(witness)", Typeable[witness.T].describe) + assertEquals("String(witness)", Typeable["witness"].describe) } @Test diff --git a/core/src/test/scala/shapeless/unions.scala b/core/src/test/scala/shapeless/unions.scala index f51a873cb..a990d554a 100644 --- a/core/src/test/scala/shapeless/unions.scala +++ b/core/src/test/scala/shapeless/unions.scala @@ -30,16 +30,11 @@ import ops.union.UnzipFields class UnionTests { - val wI = Witness("i") - type i = wI.T + type i = "i" + type s = "s" + type b = "b" - val wS = Witness("s") - type s = wS.T - - val sB = Witness("b") - type b = sB.T - - type U = Union.`"i" -> Int, "s" -> String, "b" -> Boolean`.T + type U = "i" ->> Int :+: "s" ->> String :+: "b" ->> Boolean :+: CNil @Test def testGetLiterals: Unit = { @@ -216,7 +211,7 @@ class UnionTests { val u2 = Union[U](s = "foo") val u3 = Union[U](b = true) - type UF = (Witness.`"i"`.T, Int) :+: (Witness.`"s"`.T, String) :+: (Witness.`"b"`.T, Boolean) :+: CNil + type UF = ("i", Int) :+: ("s", String) :+: ("b", Boolean) :+: CNil { val f1 = u1.fields @@ -233,7 +228,7 @@ class UnionTests { val us2 = Coproduct[US]("second" ->> Option(true)) val us3 = Coproduct[US]("third" ->> Option.empty[String]) - type USF = (Witness.`"first"`.T, Option[Int]) :+: (Witness.`"second"`.T, Option[Boolean]) :+: (Witness.`"third"`.T, Option[String]) :+: CNil + type USF = ("first", Option[Int]) :+: ("second", Option[Boolean]) :+: ("third", Option[String]) :+: CNil { val f1 = us1.fields @@ -377,18 +372,4 @@ class UnionTests { assertTypedEquals[U](Coproduct[U]("baz" ->> 2.0), r3) } } - - @Test - def testAltSyntax: Unit = { - type U0 = - Witness.`"foo"`.->>[String] :+: - Witness.`"bar"`.->>[Boolean] :+: - Witness.`"baz"`.->>[Double] :+: - CNil - - type U = Union.`"foo" -> String, "bar" -> Boolean, "baz" -> Double`.T - - implicitly[U =:= U0] - - } } From 8a7433ea37733a26ce86a67f54e0a8137acc237e Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 6 Jul 2021 16:43:54 +0200 Subject: [PATCH 18/32] Remove the poly macros --- core/src/main/scala-2/shapeless/poly.scala | 55 ---------------------- core/src/main/scala-3/shapeless/poly.scala | 26 ---------- core/src/main/scala/shapeless/poly.scala | 2 +- 3 files changed, 1 insertion(+), 82 deletions(-) delete mode 100644 core/src/main/scala-2/shapeless/poly.scala delete mode 100644 core/src/main/scala-3/shapeless/poly.scala diff --git a/core/src/main/scala-2/shapeless/poly.scala b/core/src/main/scala-2/shapeless/poly.scala deleted file mode 100644 index bb433ba4d..000000000 --- a/core/src/main/scala-2/shapeless/poly.scala +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2011-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import shapeless.PolyDefns.Case - -import language.experimental.macros - -import reflect.macros.whitebox - -trait CaseScalaCompat { - - implicit def materializeFromValue1[P, F[_], T]: Case[P, F[T] :: HNil] = - macro PolyMacros.materializeFromValueImpl[P, F[T], T] - - implicit def materializeFromValue2[P, T]: Case[P, T :: HNil] = - macro PolyMacros.materializeFromValueImpl[P, T, T] -} - -class PolyMacros(val c: whitebox.Context) { - import c.universe._ - - import PolyDefns.Case - - def materializeFromValueImpl[P: WeakTypeTag, FT: WeakTypeTag, T: WeakTypeTag]: Tree = { - val pTpe = weakTypeOf[P] - val ftTpe = weakTypeOf[FT] - val tTpe = weakTypeOf[T] - - val recTpe = weakTypeOf[Case[P, FT :: HNil]] - if(c.openImplicits.tail.exists(_.pt =:= recTpe)) - c.abort(c.enclosingPosition, s"Diverging implicit expansion for Case.Aux[$pTpe, $ftTpe :: HNil]") - - val value = pTpe match { - case SingleType(_, f) => f - case other => c.abort(c.enclosingPosition, "Can only materialize cases from singleton values") - } - - q""" $value.caseUniv[$tTpe] """ - } -} diff --git a/core/src/main/scala-3/shapeless/poly.scala b/core/src/main/scala-3/shapeless/poly.scala deleted file mode 100644 index 3889e2dd6..000000000 --- a/core/src/main/scala-3/shapeless/poly.scala +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2011-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import shapeless.PolyDefns.Case - -trait CaseScalaCompat { - - implicit def materializeFromValue1[P, F[_], T]: Case[P, F[T] :: HNil] = ??? - - implicit def materializeFromValue2[P, T]: Case[P, T :: HNil] = ??? -} diff --git a/core/src/main/scala/shapeless/poly.scala b/core/src/main/scala/shapeless/poly.scala index 2ba7316b1..4ec97e08d 100644 --- a/core/src/main/scala/shapeless/poly.scala +++ b/core/src/main/scala/shapeless/poly.scala @@ -35,7 +35,7 @@ object PolyDefns extends Cases { def apply[T, U](t: T, u: U)(implicit ev: (T :: U :: HNil) =:= L) = value(t :: u :: HNil) } - object Case extends CaseInst with CaseScalaCompat { + object Case extends CaseInst { type Aux[P, L <: HList, Result0] = Case[P, L] { type Result = Result0 } type Hom[P, T] = Aux[P, T :: HNil, T] From 4a268419d69c540314a574b69f2448e9970f2c5a Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 6 Jul 2021 16:57:39 +0200 Subject: [PATCH 19/32] Add helper to make Unions without macros --- core/src/main/scala/shapeless/coproduct.scala | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/scala/shapeless/coproduct.scala b/core/src/main/scala/shapeless/coproduct.scala index 3877b65ef..7912da86a 100644 --- a/core/src/main/scala/shapeless/coproduct.scala +++ b/core/src/main/scala/shapeless/coproduct.scala @@ -16,6 +16,8 @@ package shapeless +import shapeless.labelled.{FieldType, field} + import scala.annotation.tailrec /** Encodes a coproduct type, such as a sealed family of case classes. @@ -124,9 +126,15 @@ object Coproduct extends CoproductScalaCompat { class MkCoproduct[C <: Coproduct] { def apply[T](t: T)(implicit inj: Inject[C, T]): C = inj(t) } + + class MkUnionCoproduct[C <: Coproduct] { + def apply[K <: Singleton, T](k: K, t: T)(implicit inj: Inject[C, FieldType[K, T]]): C = inj(field[K](t)) + } def apply[C <: Coproduct] = new MkCoproduct[C] + def fromUnion[C <: Coproduct] = new MkUnionCoproduct[C] + implicit def cpOps[C <: Coproduct](c: C): CoproductOps[C] = new CoproductOps(c) def unsafeMkCoproduct(length: Int, value: Any) = From 5683f2d19202109739dcb9ed10b711a9d94a8084 Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 6 Jul 2021 16:59:11 +0200 Subject: [PATCH 20/32] Move alacarte to examples --- core/src/main/scala/shapeless/alacarte.scala | 188 ------------------ .../scala/shapeless/examples/alacarte.scala | 147 ++++++++++++++ 2 files changed, 147 insertions(+), 188 deletions(-) delete mode 100644 core/src/main/scala/shapeless/alacarte.scala diff --git a/core/src/main/scala/shapeless/alacarte.scala b/core/src/main/scala/shapeless/alacarte.scala deleted file mode 100644 index 374741a0e..000000000 --- a/core/src/main/scala/shapeless/alacarte.scala +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2014 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.reflect.ClassTag - -import record._ -import ops.hlist.{ Length, Tupler } -import ops.nat.ToInt -import ops.record.Merger - -trait CaseClassFacet { - type C -} - -trait ProductISOFacet extends CaseClassFacet { - trait ProductISOOps { - type Repr <: HList - type P <: Product - val gen: Generic.Aux[C, Repr] - val pgen: Generic.Aux[P, Repr] - - def toProduct(c: C): P = pgen.from(gen.to(c)) - def fromProduct(p: P): C = gen.from(pgen.to(p)) - } - - val ops: ProductISOOps -} - -trait ApplyUnapplyFacet extends ProductISOFacet { - trait ApplyUnapplyOps extends ProductISOOps { - def apply(p: P): C = fromProduct(p) - - def unapply(c: C): Some[P] = Some(toProduct(c)) - } - - val ops: ApplyUnapplyOps - - trait ApplyUnapplyCompanion { - @nonGeneric def apply(elems: ops.P): C = ops.apply(elems) - @nonGeneric def unapply(s: C): Some[ops.P] = ops.unapply(s) - } -} - -trait ProductFacet extends ProductISOFacet { - trait ProductOps extends ProductISOOps { - def productElement(c: C, n: Int): Any = toProduct(c).productElement(n) - - def productIterator(c: C): Iterator[Any] = toProduct(c).productIterator - - def productPrefix: String - - def productArity: Int - } - - val ops: ProductOps - - trait ProductMethods { self: C => - def productElement(n: Int): Any = ops.productElement(this, n) - - def productIterator: Iterator[Any] = ops.productIterator(this) - - def productPrefix: String = ops.productPrefix - - def productArity: Int = ops.productArity - } -} - -trait PolymorphicEqualityFacet extends ProductISOFacet { - trait PolymorphicEqualityOps extends ProductISOOps { - val typ: Typeable[C] - - def canEqual(c: C, other: Any): Boolean = typ.cast(other).isDefined - - def equals(c: C, other: Any): Boolean = - (c.asInstanceOf[AnyRef] eq other.asInstanceOf[AnyRef]) || - typ.cast(other).exists { that => - (toProduct(c) == toProduct(that)) && canEqual(that, c) - } - - def hashCode(c: C): Int = toProduct(c).hashCode - } - - val ops: PolymorphicEqualityOps - - trait PolymorphicEqualityMethods { self: C => - override def equals(other: Any): Boolean = ops.equals(this, other) - - override def hashCode: Int = ops.hashCode(this) - } -} - -trait CopyFacet extends CaseClassFacet { - trait CopyOps { - type LRepr <: HList - type CopyMerger[R <: HList] = Merger.Aux[LRepr, R, LRepr] - - val lgen: LabelledGeneric.Aux[C, LRepr] - - def copy[R <: HList](c: C, rec: R)(implicit merger: CopyMerger[R]): C = - lgen.from(lgen.to(c).merge(rec)) - } - - val ops: CopyOps - - /* - TODO RecordArgs gone - trait CopyMethods extends RecordArgs { self: C => - def copyRecord[R <: HList](rec: R)(implicit merger: ops.CopyMerger[R]): C = ops.copy(this, rec) - } - */ -} - -trait ToStringFacet extends ProductFacet { - trait ToStringOps extends ProductOps { - def toString(c: C): String = productPrefix+toProduct(c).toString - } - - val ops: ToStringOps - - trait ToStringMethods { self: C => - override def toString: String = ops.toString(this) - } -} - -trait DefaultCaseClassDefns - extends ApplyUnapplyFacet - with ProductFacet - with PolymorphicEqualityFacet - with CopyFacet - with ToStringFacet { - - trait CaseClassOps - extends ApplyUnapplyOps - with ProductOps - with PolymorphicEqualityOps - with CopyOps - with ToStringOps - - trait CaseClassCompanion extends - ApplyUnapplyCompanion - - trait CaseClass - extends ProductMethods - with PolymorphicEqualityMethods - // TODO Gone with CopyMethods - with ToStringMethods { self: C => } - - val ops: CaseClassOps - - def Ops[Repr0 <: HList, LRepr0 <: HList, P0 <: Product, N <: Nat] - (implicit - gen0: Generic.Aux[C, Repr0], - lgen0: LabelledGeneric.Aux[C, LRepr0], - len: Length.Aux[Repr0, N], - toInt: ToInt[N], - tup: Tupler.Aux[Repr0, P0], - pgen0: Generic.Aux[P0, Repr0], - typ0: Typeable[C], - tag0: ClassTag[C] - ) = - new CaseClassOps { - type Repr = Repr0 - type LRepr = LRepr0 - type P = P0 - val gen = gen0 - val lgen = lgen0 - val pgen = pgen0 - val typ = typ0 - val tag = tag0 - val productPrefix = tag0.runtimeClass.getName.split("(\\.|\\$)").last - val productArity = toInt() - } -} diff --git a/examples/src/main/scala/shapeless/examples/alacarte.scala b/examples/src/main/scala/shapeless/examples/alacarte.scala index d2ba97432..ae9147ebd 100644 --- a/examples/src/main/scala/shapeless/examples/alacarte.scala +++ b/examples/src/main/scala/shapeless/examples/alacarte.scala @@ -19,6 +19,153 @@ package examples import test._ +import scala.reflect.ClassTag + +import record._ +import ops.hlist.{ Length, Tupler } +import ops.nat.ToInt +import ops.record.Merger + +trait CaseClassFacet { + type C +} + +trait ProductISOFacet extends CaseClassFacet { + trait ProductISOOps { + type Repr <: HList + type P <: Product + val gen: Generic.Aux[C, Repr] + val pgen: Generic.Aux[P, Repr] + + def toProduct(c: C): P = pgen.from(gen.to(c)) + def fromProduct(p: P): C = gen.from(pgen.to(p)) + } + + val ops: ProductISOOps +} + +trait ApplyUnapplyFacet extends ProductISOFacet { + trait ApplyUnapplyOps extends ProductISOOps { + def apply(p: P): C = fromProduct(p) + + def unapply(c: C): Some[P] = Some(toProduct(c)) + } + + val ops: ApplyUnapplyOps + + trait ApplyUnapplyCompanion { + @nonGeneric def apply(elems: ops.P): C = ops.apply(elems) + @nonGeneric def unapply(s: C): Some[ops.P] = ops.unapply(s) + } +} + +trait ProductFacet extends ProductISOFacet { + trait ProductOps extends ProductISOOps { + def productElement(c: C, n: Int): Any = toProduct(c).productElement(n) + + def productIterator(c: C): Iterator[Any] = toProduct(c).productIterator + + def productPrefix: String + + def productArity: Int + } + + val ops: ProductOps + + trait ProductMethods { self: C => + def productElement(n: Int): Any = ops.productElement(this, n) + + def productIterator: Iterator[Any] = ops.productIterator(this) + + def productPrefix: String = ops.productPrefix + + def productArity: Int = ops.productArity + } +} + +trait PolymorphicEqualityFacet extends ProductISOFacet { + trait PolymorphicEqualityOps extends ProductISOOps { + val typ: Typeable[C] + + def canEqual(c: C, other: Any): Boolean = typ.cast(other).isDefined + + def equals(c: C, other: Any): Boolean = + (c.asInstanceOf[AnyRef] eq other.asInstanceOf[AnyRef]) || + typ.cast(other).exists { that => + (toProduct(c) == toProduct(that)) && canEqual(that, c) + } + + def hashCode(c: C): Int = toProduct(c).hashCode + } + + val ops: PolymorphicEqualityOps + + trait PolymorphicEqualityMethods { self: C => + override def equals(other: Any): Boolean = ops.equals(this, other) + + override def hashCode: Int = ops.hashCode(this) + } +} + +trait ToStringFacet extends ProductFacet { + trait ToStringOps extends ProductOps { + def toString(c: C): String = productPrefix+toProduct(c).toString + } + + val ops: ToStringOps + + trait ToStringMethods { self: C => + override def toString: String = ops.toString(this) + } +} + +trait DefaultCaseClassDefns + extends ApplyUnapplyFacet + with ProductFacet + with PolymorphicEqualityFacet + with ToStringFacet { + + trait CaseClassOps + extends ApplyUnapplyOps + with ProductOps + with PolymorphicEqualityOps + with ToStringOps + + trait CaseClassCompanion extends + ApplyUnapplyCompanion + + trait CaseClass + extends ProductMethods + with PolymorphicEqualityMethods + with ToStringMethods { self: C => } + + val ops: CaseClassOps + + def Ops[Repr0 <: HList, LRepr0 <: HList, P0 <: Product, N <: Nat] + (implicit + gen0: Generic.Aux[C, Repr0], + lgen0: LabelledGeneric.Aux[C, LRepr0], + len: Length.Aux[Repr0, N], + toInt: ToInt[N], + tup: Tupler.Aux[Repr0, P0], + pgen0: Generic.Aux[P0, Repr0], + typ0: Typeable[C], + tag0: ClassTag[C] + ) = + new CaseClassOps { + type Repr = Repr0 + type LRepr = LRepr0 + type P = P0 + val gen = gen0 + val lgen = lgen0 + val pgen = pgen0 + val typ = typ0 + val tag = tag0 + val productPrefix = tag0.runtimeClass.getName.split("(\\.|\\$)").last + val productArity = toInt() + } +} + // Almost boilerplate free case classes a la carte for any "case-class-like" // type (in particular, "case-class-like" includes non-case-classes with // lazy val fields). From 352f23e99906903a0a5d6f5c8e86782773a70747 Mon Sep 17 00:00:00 2001 From: Katrix Date: Sun, 11 Jul 2021 20:38:24 +0200 Subject: [PATCH 21/32] Widen which doesn't work --- core/src/main/scala-3/shapeless/singletons.scala | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala-3/shapeless/singletons.scala b/core/src/main/scala-3/shapeless/singletons.scala index 82d6ce0c9..74f9dcadf 100644 --- a/core/src/main/scala-3/shapeless/singletons.scala +++ b/core/src/main/scala-3/shapeless/singletons.scala @@ -16,7 +16,19 @@ package shapeless +import scala.quoted._ + trait WidenScalaCompat { - implicit def materialize[T, Out >: T]: Widen.Aux[T, Out] = ??? + transparent inline given [T <: Singleton]: Widen[T] = ${WidenScalaCompat.widenImpl[T]} +} +object WidenScalaCompat { + + def widenImpl[T](using Quotes)(using tTpe: Type[T]): Expr[Widen[T]] = { + import quotes.reflect.* + val widenType = TypeRepr.of[T].dealias.widenTermRefByName.widen.asType + widenType.asInstanceOf[Type[_ >: T]] match { + case '[out] => '{Widen.instance[T, out](t => t.asInstanceOf[out])} + } + } } From 72b8694b7fad64b565afd69fac69c846872ae6b6 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 2 Aug 2021 17:40:39 +0200 Subject: [PATCH 22/32] Implement record ops --- build.sbt | 3 +- .../src/main/scala-2/shapeless/labelled.scala | 15 ++++ .../src/main/scala-3/shapeless/generic1.scala | 9 ++- .../src/main/scala-3/shapeless/labelled.scala | 14 ++++ .../shapeless/ops/record/records.scala | 73 +++++++++++++++++-- core/src/main/scala/shapeless/labelled.scala | 15 ---- 6 files changed, 104 insertions(+), 25 deletions(-) diff --git a/build.sbt b/build.sbt index e1aee9a0a..e8959bb79 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject val Scala213 = "2.13.6" -val Scala3 = "3.0.0" +val Scala3 = "3.0.3-RC1-bin-20210801-2191757-NIGHTLY" commonSettings noPublishSettings @@ -77,6 +77,7 @@ val scalacOptionsAll = List( val scalacOptions3 = Seq( "-language:dynamics", + "-Yretain-trees" ) val scalacOptions213 = Seq( diff --git a/core/src/main/scala-2/shapeless/labelled.scala b/core/src/main/scala-2/shapeless/labelled.scala index ea36d5304..4c8beb38b 100644 --- a/core/src/main/scala-2/shapeless/labelled.scala +++ b/core/src/main/scala-2/shapeless/labelled.scala @@ -19,6 +19,21 @@ package shapeless import scala.language.experimental.macros import scala.reflect.macros.whitebox +object labelled { + + /** The type of fields with keys of singleton type `K` and value type `V`. */ + type FieldType[K, +V] = V with KeyTag[K, V] + type KeyTag[K, +V] + + type ->>[K, +V] = FieldType[K, V] + + /** Yields a result encoding the supplied value with the singleton type `K` of its key. */ + def field[K]: FieldBuilder[K] = new FieldBuilder(true) + class FieldBuilder[K](private val dummy: Boolean) extends AnyVal { + def apply[V](v: V): FieldType[K, V] = v.asInstanceOf[FieldType[K, V]] + } +} + trait LabellingScalaCompat { implicit def mkLabelling[T]: Labelling[T] = diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index f4e5ce835..b5e312120 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -201,6 +201,7 @@ trait IsCCons1ScalaCompat { } trait IsCCons10ScalaCompat { + given fromSum[L[_], FH[_[_]], FT[_[_]]]( using m: MirrorOf1Sum[L], fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], @@ -209,10 +210,10 @@ trait IsCCons10ScalaCompat { override type H[Z] = Head[m.MirroredElemTypes[Z]] override type T[Z] = Coproduct.TupleToCoproduct[Tail[m.MirroredElemTypes[Z]]] - override def pack[Z](u: Either[H[Z], T[Z]]): L[Z] = u match { - case Left(hz) => hz.asInstanceOf[L[Z]] - case Right(tz) => Coproduct.extractCoproduct(tz).asInstanceOf[L[Z]] - } + override def pack[Z](u: Either[H[Z], T[Z]]): L[Z] = ??? /*u match { + case Left(hz) => ??? //hz.asInstanceOf[L[Z]] + case Right(tz) => ??? //Coproduct.extractCoproduct(tz).asInstanceOf[L[Z]] + }*/ override def unpack[Z](p: L[Z]): Either[H[Z], T[Z]] = { //TODO: Make sure this is correct diff --git a/core/src/main/scala-3/shapeless/labelled.scala b/core/src/main/scala-3/shapeless/labelled.scala index fb5df6a86..0c24fcfc2 100644 --- a/core/src/main/scala-3/shapeless/labelled.scala +++ b/core/src/main/scala-3/shapeless/labelled.scala @@ -19,6 +19,20 @@ package shapeless import scala.deriving._ import scala.compiletime._ +object labelled { + + /** The type of fields with keys of singleton type `K` and value type `V`. */ + opaque type FieldType[K, +V] <: V = V + + type ->>[K, +V] = FieldType[K, V] + + /** Yields a result encoding the supplied value with the singleton type `K` of its key. */ + def field[K]: FieldBuilder[K] = new FieldBuilder(true) + class FieldBuilder[K](private val dummy: Boolean) extends AnyVal { + def apply[V](v: V): FieldType[K, V] = v.asInstanceOf[FieldType[K, V]] + } +} + trait LabellingScalaCompat { inline given [T](using m: Mirror.Of[T]): Labelling.Aux[T, HList.TupleToHList[m.MirroredElemLabels]] = { diff --git a/core/src/main/scala-3/shapeless/ops/record/records.scala b/core/src/main/scala-3/shapeless/ops/record/records.scala index 8a94832be..2bae27d9c 100644 --- a/core/src/main/scala-3/shapeless/ops/record/records.scala +++ b/core/src/main/scala-3/shapeless/ops/record/records.scala @@ -18,24 +18,87 @@ package shapeless package ops package record +import shapeless.labelled.FieldType + +import scala.compiletime.ops.int.S + +type FindField[R <: HList, K] = FindField0[R, K, 0] +type FindField0[R <: HList, K, I <: Int] <: (Any, Int) = R match { + case FieldType[K, f] :: t => (f, I) + case _ :: t => FindField0[t, K, S[I]] +} + trait SelectorScalaCompat { - implicit def materialize[R <: HList, K, O]: Selector.Aux[R, K, O] = ??? + given[R <: HList, K]( + using idx: ValueOf[scala.Tuple.Elem[FindField[R, K], 1]] + ): Selector.Aux[R, K, scala.Tuple.Head[FindField[R, K]]] = + new UnsafeSelector(idx.value).asInstanceOf[Selector.Aux[R, K, scala.Tuple.Head[FindField[R, K]]]] +} + +type IndexOf[L <: HList, E] = IndexOf0[L, E, 0] +type IndexOf0[L <: HList, E, I <: Int] <: Int = L match { + case E :: _ => I + case _ :: t => IndexOf0[t, E, S[I]] + case HNil => -1 +} + +type Append[L <: HList, E] <: HList = L match { + case h :: t => h :: Append[t, E] + case HNil => E :: HNil +} + +type IfEq[A, B, IfTrue, IfFalse] <: IfTrue | IfFalse = A match { + case B => IfTrue + case _ => IfFalse } trait UpdaterScalaCompat { - implicit def meterialize[L <: HList, F, O <: HList]: Updater.Aux[L, F, O] = ??? + given [L <: HList, F]( + using idx: ValueOf[IndexOf[L, F]] + ): Updater.Aux[L, F, IfEq[IndexOf[L, F], -1, Append[L, F], L]] = + new UnsafeUpdater(idx.value).asInstanceOf[Updater.Aux[L, F, IfEq[IndexOf[L, F], -1, Append[L, F], L]]] +} + +type ReplaceField[R <: HList, K, B] <: HList = R match { + case FieldType[K, _] :: t => FieldType[K, B] :: t + case h :: t => h :: ReplaceField[t, K, B] + case HNil => HNil } trait ModifierScalaCompat { - implicit def materialize[R <: HList, K, A, B, O <: HList]: Modifier.Aux[R, K, A, B, O] = ??? + given [R <: HList, K, A, B]( + using ev: scala.Tuple.Head[FindField[R, K]] <:< A, + idx: ValueOf[scala.Tuple.Elem[FindField[R, K], 1]] + ): Modifier.Aux[R, K, A, B, ReplaceField[R, K, B]] = + new UnsafeModifier(idx.value).asInstanceOf[Modifier.Aux[R, K, A, B, ReplaceField[R, K, B]]] +} + +type ReversePrependHList[L <: HList, M <: HList] <: HList = L match { + case HNil => M + case h :: t => ReversePrependHList[t, h :: M] +} + +type RemoveField[R <: HList, K] = RemoveField0[R, K, 0, HNil] +type RemoveField0[R <: HList, K, I <: Int, Acc <: HList] <: (Int, Any, HList) = R match { + case FieldType[K, f] :: t => (I, f, ReversePrependHList[Acc, t]) + case h :: t => RemoveField0[t, K, S[I], h :: Acc] } trait RemoverScalaCompat { - implicit def materialize[R <: HList, K, V, O <: HList]: Remover.Aux[R, K, (V, O)] = ??? + given [R <: HList, K]( + using idx: ValueOf[scala.Tuple.Head[RemoveField[R, K]]] + ): Remover.Aux[R, K, scala.Tuple.Tail[RemoveField[R, K]]] = + new UnsafeRemover(idx.value).asInstanceOf[Remover.Aux[R, K, scala.Tuple.Tail[RemoveField[R, K]]]] +} + +type HasNoKey[R <: HList, K] <: Boolean = R match { + case FieldType[K, _] :: _ => false + case _ :: t => HasNoKey[t, K] + case HNil => true } trait LacksKeyScalaCompat { - implicit def materialize[R <: HList, K]: LacksKey[R, K] = ??? + given [R <: HList, K](using HasNoKey[R, K] =:= true): LacksKey[R, K] = new LacksKey[R, K] } diff --git a/core/src/main/scala/shapeless/labelled.scala b/core/src/main/scala/shapeless/labelled.scala index 2b953b6b0..bffa774fb 100644 --- a/core/src/main/scala/shapeless/labelled.scala +++ b/core/src/main/scala/shapeless/labelled.scala @@ -16,21 +16,6 @@ package shapeless -object labelled { - - /** The type of fields with keys of singleton type `K` and value type `V`. */ - type FieldType[K, +V] = V with KeyTag[K, V] - type KeyTag[K, +V] - - type ->>[K, +V] = FieldType[K, V] - - /** Yields a result encoding the supplied value with the singleton type `K` of its key. */ - def field[K]: FieldBuilder[K] = new FieldBuilder(true) - class FieldBuilder[K](private val dummy: Boolean) extends AnyVal { - def apply[V](v: V): FieldType[K, V] = v.asInstanceOf[FieldType[K, V]] - } -} - trait Labelling[T] extends DepFn0 with Serializable { type Out <: HList } object Labelling extends LabellingScalaCompat { From 317feea0fdfbb293ab864f59ea59ca165bf15963 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 2 Aug 2021 17:40:59 +0200 Subject: [PATCH 23/32] Implement Default --- core/src/main/scala-3/shapeless/default.scala | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala-3/shapeless/default.scala b/core/src/main/scala-3/shapeless/default.scala index ef91bfb9e..8251bf362 100644 --- a/core/src/main/scala-3/shapeless/default.scala +++ b/core/src/main/scala-3/shapeless/default.scala @@ -1,5 +1,67 @@ package shapeless +import scala.quoted.* + trait DefaultScalaCompat { - implicit def materialize[T, L <: HList]: Default.Aux[T, L] = ??? + transparent inline given materialize[T]: Default[T] = ${DefaultScalaCompat.defaultImpl[T]} +} + +object DefaultScalaCompat { + def defaultImpl[T: Type](using quotes: Quotes): Expr[Default[T]] = { + import quotes.reflect.* + val tpe = TypeRepr.of[T] + + val defaultConstructorMethodNames = "$lessinit$greater$default$" + + tpe.classSymbol match { + case Some(classSymbol) => + val constructorParams = classSymbol.primaryConstructor.paramSymss + if(constructorParams.sizeIs > 1) { + report.throwError(s"Found more than one parameter list for ${tpe.show}") + } + + val constructorParamsSize = constructorParams.head.size + + val moduleClass = classSymbol.companionModule.moduleClass + val defaultMethods = (1 to constructorParamsSize).map { i => + moduleClass.declaredMethod(defaultConstructorMethodNames + i).headOption + } + + val defaultExprs = defaultMethods.map { + case Some(method) => + val DefDef(_, _, _, optDefault) = method.tree + val default = optDefault.getOrElse( + report.throwError("Found empty tree for default. Make sure that the compiler option -Yretain-trees is enabled") + ) + + default.asExpr match { + case '{$defaultExpr: t} => + defaultExpr.asTerm.tpe.widen.asType match { + case '[t2] => '{Some($defaultExpr.asInstanceOf[t2])} + } + + //'{Some($defaultExpr)} + } + + case None => '{None} + } + + def result[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[Any]]): Expr[Default[T]] = + rest match { + case Nil => '{ + new Default[T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + case Seq('{$head: tpe}, tail*) => + result('{new ::($head, $acc)}, tail) + } + + result('{HNil: HNil}, defaultExprs.reverse) + + case _ => + report.throwError(s"Invalid type ${tpe.show}. Expected a class.") + } + } } From aee7fff1f93c58ee31d5f3d788295ee5f7441d15 Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 2 Aug 2021 17:41:18 +0200 Subject: [PATCH 24/32] Implement Typeable --- .../src/main/scala-2/shapeless/typeable.scala | 53 +++ .../src/main/scala-3/shapeless/typeable.scala | 315 +++++++++++++++++- core/src/main/scala/shapeless/typeable.scala | 73 ++-- 3 files changed, 389 insertions(+), 52 deletions(-) diff --git a/core/src/main/scala-2/shapeless/typeable.scala b/core/src/main/scala-2/shapeless/typeable.scala index 65094bad7..6cc4563ab 100644 --- a/core/src/main/scala-2/shapeless/typeable.scala +++ b/core/src/main/scala-2/shapeless/typeable.scala @@ -16,9 +16,62 @@ package shapeless +import shapeless.Typeable.{instance, safeSimpleName} + import scala.language.experimental.macros import scala.reflect.macros.blackbox +trait TypeableScalaCompat { + + /** + * Typeable instance for singleton reference types + * + * @param value The singleton value + * + * @param name The name of the singleton + * + * @param serializable Whether the instance should be + * serializable. For singleton types of object definitions + * and symbols, this should be true, since they preserve + * their identity after serialization/deserialization. + * For other cases, it should be false, since the deserialized + * instance wouldn't work correctly. + */ + def referenceSingletonTypeable[T <: AnyRef](value: T, name: String, serializable: Boolean): Typeable[T] = + new Typeable[T] { + def describe = s"$name.type" + + def cast(t: Any): Option[T] = + if (t.asInstanceOf[AnyRef] eq value) Some(value) else None + + @throws(classOf[java.io.IOException]) + private def writeObject(out: java.io.ObjectOutputStream): Unit = + if (serializable) out.defaultWriteObject() + else throw new java.io.NotSerializableException("referenceSingletonTypeable") + } + + /** Typeable instance for intersection types with typeable parents */ + def intersectionTypeable[T](parents: Array[Typeable[_]]): Typeable[T] = + instance(parents.map(_.describe).mkString(" with ")) { t => + if (t != null && parents.forall(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } + + /** Typeable instance for polymorphic case classes with typeable elements */ + def caseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]]): Typeable[T] = + namedCaseClassTypeable(erased, fields, safeSimpleName(erased)) + + /** Typeable instance for polymorphic case classes with typeable elements, specifying the name explicitly. */ + def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = + instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => + if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { + val cp = t.asInstanceOf[Product] + val ct = t.asInstanceOf[T] + val f = cp.productIterator.toList + if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None + } else None + } +} + trait LowPriorityTypeableScalaCompat { implicit def dfltTypeable[T]: Typeable[T] = macro TypeableMacros.dfltTypeableImpl[T] } diff --git a/core/src/main/scala-3/shapeless/typeable.scala b/core/src/main/scala-3/shapeless/typeable.scala index 96dedde07..999d8375c 100644 --- a/core/src/main/scala-3/shapeless/typeable.scala +++ b/core/src/main/scala-3/shapeless/typeable.scala @@ -16,6 +16,319 @@ package shapeless +import scala.annotation.tailrec +import scala.compiletime.* +import scala.quoted.* +import scala.deriving.* +import shapeless.Typeable.{instance, safeSimpleName} + +trait TypeableScalaCompat { + + /** + * Typeable instance for singleton reference types + * + * @param value The singleton value + * + * @param name The name of the singleton + * + * @param serializable Whether the instance should be + * serializable. For singleton types of object definitions + * and symbols, this should be true, since they preserve + * their identity after serialization/deserialization. + * For other cases, it should be false, since the deserialized + * instance wouldn't work correctly. + */ + def referenceSingletonTypeable[T](value: T, name: String, serializable: Boolean): Typeable[T] = + new Typeable[T] { + def describe = s"$name.type" + + def cast(t: Any): Option[T] = + if (t.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) Some(value) else None + + @throws(classOf[java.io.IOException]) + private def writeObject(out: java.io.ObjectOutputStream): Unit = + if (serializable) out.defaultWriteObject() + else throw new java.io.NotSerializableException("referenceSingletonTypeable") + } + + /** Typeable instance for intersection types with typeable parents */ + def intersectionTypeable[T](parents: Array[Typeable[_]]): Typeable[T] = + instance(parents.map(_.describe).mkString(" & ")) { t => + if (t != null && parents.forall(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } + + /** Typeable instance for union types with typeable disjuncts */ + def unionTypeable[T](parents: Seq[Typeable[_]]): Typeable[T] = + instance(parents.map(_.describe).mkString(" | ")) { t => + if (t != null && parents.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } + + /** Typeable instance for polymorphic case classes with typeable elements */ + def caseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]]): Typeable[T] = + namedCaseClassTypeable(erased, fields, s"${safeSimpleName(erased)}[${fields.map(_.describe).mkString(",")}]") + + /** Typeable instance for polymorphic case classes with typeable elements, specifying the name explicitly. */ + def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = + instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => + if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { + val cp = t.asInstanceOf[Product] + val ct = t.asInstanceOf[T] + val f = cp.productIterator.toList + if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None + } else None + } + + /** Typeable instance for polymorphic sums with typeable elements. */ + def namedSumTypeable[T](elems: Seq[Typeable[_]], name: String): Typeable[T] = + instance(name) { t => + if (elems.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } +} + trait LowPriorityTypeableScalaCompat { - implicit def dfltTypeable[T]: Typeable[T] = ??? + inline def mkDefaultTypeable[T]: Typeable[T] = ${ LowPriorityTypeableScalaCompat.impl[T] } + + inline given [T]: Typeable[T] = mkDefaultTypeable[T] +} + +object LowPriorityTypeableScalaCompat { + import Typeable._ + + def impl[T: Type](using Quotes): Expr[Typeable[T]] = { + import quotes.reflect._ + import util._ + + val TypeableType = TypeRepr.of[Typeable[_]] match { + case tp: AppliedType => tp.tycon + } + + val target = TypeRepr.of[T] + + def isAbstract(tp: TypeRepr): Boolean = + tp.typeSymbol.isAbstractType || + (tp match { + case tp: AppliedType => + isAbstract(tp.tycon) || tp.args.exists(isAbstract) + case _ => false + }) + + def normalize(tp: TypeRepr): TypeRepr = tp match { + case tp: TypeBounds => tp.low + case tp => tp + } + + def simpleName(tp: TypeRepr): String = + normalize(tp).dealias match { + case tp: AppliedType => + simpleName(tp.tycon) + tp.args.map(simpleName).mkString("[", ", ", "]") + case TypeRef(_, name) => name + case tp => tp.show + } + + def collectConjuncts(tp: TypeRepr): List[TypeRepr] = tp match { + case tp: AndType => + collectConjuncts(tp.left) ++ collectConjuncts(tp.right) + case tp => List(tp) + } + + def collectDisjuncts(tp: TypeRepr): List[TypeRepr] = tp match { + case tp: OrType => + collectDisjuncts(tp.left) ++ collectDisjuncts(tp.right) + case tp => List(tp) + } + + def summonAllTypeables(tps: Seq[TypeRepr]): Option[Expr[Seq[Typeable[_]]]] = { + val ttps = tps.map(tp => TypeableType.appliedTo(tp)) + val instances = ttps.flatMap(ttp => Implicits.search(ttp) match { + case iss: ImplicitSearchSuccess => List(iss.tree.asExprOf[Typeable[_]]) + case _: ImplicitSearchFailure => Nil + }) + + if (tps.length == instances.length) Some(Expr.ofSeq(instances)) + else None + } + + def mkCaseClassTypeable = { + val sym = target.classSymbol.get + val fields = sym.declaredFields + val caseFields = sym.caseFields.filter(f => fields.contains(f)) + def fieldTpe(f: Symbol) = f.tree match { + case tree: ValDef => tree.tpt.tpe + } + if (!fields.forall(f => caseFields.contains(f) || !isAbstract(fieldTpe(f)))) { + report.throwError(s"No Typeable for case class ${target.show} with non-case fields") + } else { + val fieldTps = caseFields.map(f => target.memberType(f)) + summonAllTypeables(fieldTps) match { + case None => + report.throwError(s"Missing Typeable for field of case class ${target.show}") + case Some(ftps) => + val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] + val name = Expr(simpleName(target)) + + '{ namedCaseClassTypeable($clazz, $ftps.toArray, $name) } + } + } + } + + def mkSumTypeable = { + val r = new ReflectionUtils(quotes) + import r._ + + Mirror(target) match { + case Some(rm) => + val elemTps = rm.MirroredElemTypes + summonAllTypeables(elemTps) match { + case None => + report.throwError(s"Missing Typeable for child of sum type ${target.show}") + case Some(etps) => + val name = Expr(simpleName(target)) + + '{ namedSumTypeable[T]($etps, $name) } + } + + case None => + report.throwError(s"Typeable for sum type ${target.show} with no Mirror") + } + } + + def mkNamedSimpleTypeable = { + val name = Expr(simpleName(target)) + val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] + '{ namedSimpleTypeable($clazz, $name) } + } + + target.dealias match { + case tp: TermRef => + val ident = Ident(tp).asExprOf[T] + val sym = tp.termSymbol + val name = Expr(sym.name.toString) + val serializable = Expr(sym.flags.is(Flags.Module)) + '{ referenceSingletonTypeable[T]($ident, $name, $serializable) } + + case ConstantType(c) => + val value = Literal(c).asExprOf[T] + val name = Expr(target.widen.typeSymbol.name.toString) + '{ valueSingletonTypeable[T]($value, $name) } + + case tp: TypeRef => + val qual = tp.qualifier match { + case NoPrefix() => None + case tp: ThisType => Some(tp.tref) + case tp => Some(tp) + } + + val sym = tp.typeSymbol + + def normalizeModuleClass(sym: Symbol): Symbol = + if (sym.flags.is(Flags.Module)) sym.companionModule else sym + + val owner = normalizeModuleClass(sym.owner) + + qual match { + case Some(_) if sym.flags.is(Flags.Case) => mkCaseClassTypeable + case None => + mkNamedSimpleTypeable + case Some(tp: TypeRef) if normalizeModuleClass(tp.typeSymbol) == owner => + mkNamedSimpleTypeable + case Some(tp: TermRef) if normalizeModuleClass(tp.termSymbol) == owner => + mkNamedSimpleTypeable + case Some(_) if sym.flags.is(Flags.Sealed) => mkSumTypeable + case _ => + report.throwError(s"No Typeable for type ${target.show} with a dependent prefix") + } + + case tp: AppliedType => + val tycon = tp.tycon + val args = tp.args + + if (tp.typeSymbol.flags.is(Flags.Case)) mkCaseClassTypeable + else if (tp.typeSymbol.flags.is(Flags.Sealed)) mkSumTypeable + else report.throwError(s"No Typeable for parametrized type ${target.show}") + + + case tp: AndType => + val conjuncts = collectConjuncts(tp) + summonAllTypeables(conjuncts) match { + case Some(ctps) => + '{ intersectionTypeable($ctps.toArray) } + case None => + report.throwError(s"No Typeable for & type ${target.show} with missing conjunct(s)") + } + + case tp: OrType => + val disjuncts = collectDisjuncts(tp) + summonAllTypeables(disjuncts) match { + case Some(dtps) => + '{ unionTypeable($dtps) } + case None => + report.throwError(s"No Typeable for | type ${target.show} with missing disjunct(s)") + } + + case other => + report.throwError(s"No Typeable for type ${target.show}") + } + } +} + +class ReflectionUtils[Q <: Quotes & Singleton](val q: Q) { + given q.type = q + import q.reflect._ + + case class Mirror( + MirroredType: TypeRepr, + MirroredMonoType: TypeRepr, + MirroredElemTypes: Seq[TypeRepr], + MirroredLabel: String, + MirroredElemLabels: Seq[String] + ) + + object Mirror { + def apply(mirror: Expr[scala.deriving.Mirror]): Option[Mirror] = { + val mirrorTpe = mirror.asTerm.tpe.widen + for { + mt <- findMemberType(mirrorTpe, "MirroredType") + mmt <- findMemberType(mirrorTpe, "MirroredMonoType") + mets <- findMemberType(mirrorTpe, "MirroredElemTypes") + ml <- findMemberType(mirrorTpe, "MirroredLabel") + mels <- findMemberType(mirrorTpe, "MirroredElemLabels") + } yield { + val mets0 = tupleTypeElements(mets) + val ConstantType(StringConstant(ml0)) = ml + val mels0 = tupleTypeElements(mels).map { case ConstantType(StringConstant(l)) => l } + Mirror(mt, mmt, mets0, ml0, mels0) + } + } + + def apply(tpe: TypeRepr): Option[Mirror] = { + val MirrorType = TypeRepr.of[scala.deriving.Mirror] + + val mtpe = Refinement(MirrorType, "MirroredType", TypeBounds(tpe, tpe)) + val instance = Implicits.search(mtpe) match { + case iss: ImplicitSearchSuccess => Some(iss.tree.asExprOf[scala.deriving.Mirror]) + case _: ImplicitSearchFailure => None + } + instance.flatMap(Mirror(_)) + } + } + + def tupleTypeElements(tp: TypeRepr): List[TypeRepr] = { + @tailrec def loop(tp: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tp match { + case AppliedType(pairTpe, List(hd: TypeRepr, tl: TypeRepr)) => loop(tl, hd :: acc) + case _ => acc + } + loop(tp, Nil).reverse + } + + def low(tp: TypeRepr): TypeRepr = tp match { + case tp: TypeBounds => tp.low + case tp => tp + } + + def findMemberType(tp: TypeRepr, name: String): Option[TypeRepr] = tp match { + case Refinement(_, `name`, tp) => Some(low(tp)) + case Refinement(parent, _, _) => findMemberType(parent, name) + case AndType(left, right) => findMemberType(left, name).orElse(findMemberType(right, name)) + case _ => None + } } diff --git a/core/src/main/scala/shapeless/typeable.scala b/core/src/main/scala/shapeless/typeable.scala index b86c483bc..77895b86e 100644 --- a/core/src/main/scala/shapeless/typeable.scala +++ b/core/src/main/scala/shapeless/typeable.scala @@ -33,7 +33,7 @@ trait LowPriorityTypeable extends LowPriorityTypeableScalaCompat * Provides instances of `Typeable`. Also provides an implicit conversion which enhances arbitrary values with a * `cast[T]` method. */ -object Typeable extends TupleTypeableInstances with LowPriorityTypeable { +object Typeable extends TupleTypeableInstances with TypeableScalaCompat with LowPriorityTypeable { import java.{ lang => jl } import scala.reflect.ClassTag import syntax.typeable._ @@ -71,6 +71,25 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { /** Typeable instance for `Unit`. */ implicit val unitTypeable: Typeable[Unit] = ValueTypeable[Unit, runtime.BoxedUnit](classOf[runtime.BoxedUnit], "Unit") + /** Typeable instance for `java.lang.Byte`. */ + implicit val jlByteTypeable: Typeable[jl.Byte] = ValueTypeable[jl.Byte, jl.Byte](classOf[jl.Byte], "java.lang.Byte") + /** Typeable instance for `java.lang.Short`. */ + implicit val jlShortTypeable: Typeable[jl.Short] = ValueTypeable[jl.Short, jl.Short](classOf[jl.Short], "java.lang.Short") + /** Typeable instance for `java.lang.Character`. */ + implicit val jlCharacterTypeable: Typeable[jl.Character] = ValueTypeable[jl.Character, jl.Character](classOf[jl.Character], "java.lang.Character") + /** Typeable instance for `java.lang.Integer`. */ + implicit val jlIntegerTypeable: Typeable[jl.Integer] = ValueTypeable[jl.Integer, jl.Integer](classOf[jl.Integer], "java.lang.Integer") + /** Typeable instance for `java.lang.Long`. */ + implicit val jlLongTypeable: Typeable[jl.Long] = ValueTypeable[jl.Long, jl.Long](classOf[jl.Long], "java.lang.Long") + /** Typeable instance for `java.lang.Float`. */ + implicit val jlFloatTypeable: Typeable[jl.Float] = ValueTypeable[jl.Float, jl.Float](classOf[jl.Float], "java.lang.Float") + /** Typeable instance for `java.lang.Double`. */ + implicit val jlDoubleTypeable: Typeable[jl.Double] = ValueTypeable[jl.Double, jl.Double](classOf[jl.Double], "java.lang.Double") + /** Typeable instance for `java.lang.Boolean`. */ + implicit val jlBooleanTypeable: Typeable[jl.Boolean] = ValueTypeable[jl.Boolean, jl.Boolean](classOf[jl.Boolean], "java.lang.Boolean") + /** Typeable instance for `scala.runtime.BoxedUnit`. */ + implicit val srBoxedUnitTypeable: Typeable[runtime.BoxedUnit] = ValueTypeable[runtime.BoxedUnit, runtime.BoxedUnit](classOf[runtime.BoxedUnit], "scala.runtime.BoxedUnit") + def isValClass[T](clazz: Class[T]) = clazz == classOf[jl.Byte] || clazz == classOf[jl.Short] || @@ -116,39 +135,6 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { /** Typeable instance for singleton reference types (not serializable by default) */ def referenceSingletonTypeable[T <: AnyRef](value: T, name: String): Typeable[T] = referenceSingletonTypeable(value, name, serializable = false) - - /** - * Typeable instance for singleton reference types - * - * @param value The singleton value - * - * @param name The name of the singleton - * - * @param serializable Whether the instance should be - * serializable. For singleton types of object definitions - * and symbols, this should be true, since they preserve - * their identity after serialization/deserialization. - * For other cases, it should be false, since the deserialized - * instance wouldn't work correctly. - */ - def referenceSingletonTypeable[T <: AnyRef](value: T, name: String, serializable: Boolean): Typeable[T] = - new Typeable[T] { - def describe = s"$name.type" - - def cast(t: Any): Option[T] = - if (t.asInstanceOf[AnyRef] eq value) Some(value) else None - - @throws(classOf[java.io.IOException]) - private def writeObject(out: java.io.ObjectOutputStream): Unit = - if (serializable) out.defaultWriteObject() - else throw new java.io.NotSerializableException("referenceSingletonTypeable") - } - - /** Typeable instance for intersection types with typeable parents */ - def intersectionTypeable[T](parents: Array[Typeable[_]]): Typeable[T] = - instance(parents.map(_.describe).mkString(" with ")) { t => - if (t != null && parents.forall(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None - } /** Typeable instance for `Option`. */ implicit def optionTypeable[T](implicit castT: Typeable[T]): Typeable[Option[T]] = @@ -211,21 +197,6 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { } else None } - /** Typeable instance for polymorphic case classes with typeable elements */ - def caseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]]): Typeable[T] = - namedCaseClassTypeable(erased, fields, safeSimpleName(erased)) - - /** Typeable instance for polymorphic case classes with typeable elements, specifying the name explicitly. */ - def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = - instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => - if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { - val cp = t.asInstanceOf[Product] - val ct = t.asInstanceOf[T] - val f = cp.productIterator.toList - if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None - } else None - } - /** Typeable instance for `HNil`. */ implicit val hnilTypeable: Typeable[HNil] = instance("HNil") { t => if (t != null && t.isInstanceOf[HNil]) Some(t.asInstanceOf[HNil]) else None @@ -274,11 +245,11 @@ object Typeable extends TupleTypeableInstances with LowPriorityTypeable { } // Workaround for https://issues.scala-lang.org/browse/SI-5425 - private def safeSimpleName(erased: Class[_]): String = + private[shapeless] def safeSimpleName(erased: Class[_]): String = try erased.getSimpleName catch { case _: InternalError => erased.getName } - private def safeSimpleName(tag: ClassTag[_]): String = + private[shapeless] def safeSimpleName(tag: ClassTag[_]): String = safeSimpleName(tag.runtimeClass) } From 6051fb2043181587c761bb8653764dca724963cf Mon Sep 17 00:00:00 2001 From: Katrix Date: Mon, 2 Aug 2021 17:41:33 +0200 Subject: [PATCH 25/32] Some cleanup --- core/src/main/scala-3/shapeless/default.scala | 2 -- core/src/main/scala-3/shapeless/records.scala | 9 +++------ core/src/main/scala-3/shapeless/unions.scala | 12 ++++-------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/core/src/main/scala-3/shapeless/default.scala b/core/src/main/scala-3/shapeless/default.scala index 8251bf362..23a8a4c06 100644 --- a/core/src/main/scala-3/shapeless/default.scala +++ b/core/src/main/scala-3/shapeless/default.scala @@ -39,8 +39,6 @@ object DefaultScalaCompat { defaultExpr.asTerm.tpe.widen.asType match { case '[t2] => '{Some($defaultExpr.asInstanceOf[t2])} } - - //'{Some($defaultExpr)} } case None => '{None} diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala index dc773f4c0..ed8a9e2ac 100644 --- a/core/src/main/scala-3/shapeless/records.scala +++ b/core/src/main/scala-3/shapeless/records.scala @@ -35,8 +35,7 @@ object RecordScalaCompat { import quotes.reflect.report val methodString = method.valueOrError if methodString != "apply" then - report.error(s"this method must be called as 'apply' not '$methodString'") - '{???} + report.throwError(s"this method must be called as 'apply' not '$methodString'") rec match { case Varargs(values) => @@ -52,15 +51,13 @@ object RecordScalaCompat { } case _ => - report.error("Got invalid arguments in varargs") - '{???} + report.throwError("Got invalid arguments in varargs") } transform('{HNil}, values.reverse) case _ => - report.error("this method must be called with vararg arguments") - '{???} + report.throwError("this method must be called with vararg arguments") } } } diff --git a/core/src/main/scala-3/shapeless/unions.scala b/core/src/main/scala-3/shapeless/unions.scala index 24261d64d..528ba5a4a 100644 --- a/core/src/main/scala-3/shapeless/unions.scala +++ b/core/src/main/scala-3/shapeless/unions.scala @@ -29,8 +29,7 @@ object UnionScalaCompat { import quotes.reflect.report val methodString = method.valueOrError if methodString != "apply" then - report.error(s"this method must be called as 'apply' not '$methodString'") - '{???} + report.throwError(s"this method must be called as 'apply' not '$methodString'") rec match { case Varargs(Seq('{($keyExpr: String, $value: tp)})) => @@ -43,18 +42,15 @@ object UnionScalaCompat { Expr.summon[ops.coproduct.Inject[U, FieldType[keyTpe, tp]]] match { case Some(injectExpr) => '{$injectExpr($value.asInstanceOf[FieldType[keyTpe, tp]])} case None => - report.error("Can not inject into coproduct") - '{???} + report.throwError("Can not inject into coproduct") } } case Varargs(_) => - report.error("only one branch of a union may be inhabited") - '{???} + report.throwError("only one branch of a union may be inhabited") case _ => - report.error("this method must be called with vararg arguments") - '{???} + report.throwError("this method must be called with vararg arguments") } } } From e1560af25fa55fbdefecd4ac3d93f2f26a7a48de Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 3 Aug 2021 02:11:48 +0200 Subject: [PATCH 26/32] Start of Annotations impl --- .../main/scala-3/shapeless/annotation.scala | 133 +++++++++++++++++- .../scala-3/shapeless/versionspecifics.scala | 14 ++ 2 files changed, 141 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala-3/shapeless/annotation.scala b/core/src/main/scala-3/shapeless/annotation.scala index 375a7fb54..58e4d3686 100644 --- a/core/src/main/scala-3/shapeless/annotation.scala +++ b/core/src/main/scala-3/shapeless/annotation.scala @@ -16,23 +16,144 @@ package shapeless +import scala.compiletime.* +import scala.deriving.* +import scala.quoted.* + trait AnnotationScalaCompat { - implicit def materialize[A, T]: Annotation[A, T] = ??? - implicit def materializeOption[A, T]: Annotation[Option[A], T] = ??? + inline given[A, T]: Annotation[A, T] = ${AnnotationMacros.singleAnnotationForType[A, T]} + inline given[A, T]: Annotation[Option[A], T] = ${AnnotationMacros.singleOptAnnotationForType[A, T]} } trait AnnotationsScalaCompat { - implicit def materialize[A, T, Out <: HList]: Annotations.Aux[A, T, Out] = ??? + inline transparent given[A, T]: Annotations[A, T] = ${AnnotationMacros.allAnnotations[A, T]} } trait TypeAnnotationsScalaCompat { - implicit def materialize[A, T, Out <: HList]: TypeAnnotations.Aux[A, T, Out] = ??? + inline transparent given[A, T]: TypeAnnotations[A, T] = ${AnnotationMacros.allTypeAnnotations[A, T]} } trait AllAnnotationsScalaCompat { - implicit def materialize[T, Out <: HList]: AllAnnotations.Aux[T, Out] = ??? + inline transparent given[T]: AllAnnotations[T] = ${AnnotationMacros.allAnnotationsForType[T]} } trait AllTypeAnnotationsScalaCompat { - implicit def materialize[T, Out <: HList]: AllTypeAnnotations.Aux[T, Out] = ??? + inline transparent given[T]: AllTypeAnnotations[T] = ${AnnotationMacros.allTypeAnnotationsForType[T]} +} + +object AnnotationMacros { + + private def errorIfInvalidAnnotation[A: Type](using quotes: Quotes): Unit = { + import quotes.reflect.* + + val tpe = TypeRepr.of[A] + val flags = tpe.typeSymbol.flags + if (flags.is(Flags.Abstract) || flags.is(Flags.Trait)) { + report.throwError(s"Bad annotation type ${tpe.show} is abstract") + } + } + + private def findAnnotation[A: Type](using quotes: Quotes)(symbol: quotes.reflect.Symbol): Option[Expr[A]] = { + import quotes.reflect.* + val annotationType = TypeRepr.of[A] + symbol.annotations.find(_.tpe <:< annotationType).map(_.asExprOf[A]) + } + + private def singleAnnotationForTypeCommon[A: Type, T: Type](using quotes: Quotes): Option[Expr[A]] = { + import quotes.reflect.* + errorIfInvalidAnnotation[A] + findAnnotation[A](TypeRepr.of[T].typeSymbol) + } + + def singleAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[A, T]] = { + import quotes.reflect.* + singleAnnotationForTypeCommon[A, T] match { + case Some(expr) => '{Annotation.mkAnnotation($expr)} + case None => report.throwError(s"No ${Type.show[A]} annotation found on ${Type.show[T]}") + } + } + + def singleOptAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[Option[A], T]] = { + import quotes.reflect.* + singleAnnotationForTypeCommon[A, T] match { + case Some(expr) => '{Annotation.mkAnnotation(Some($expr))} + case None => '{Annotation.mkAnnotation(None)} + } + } + + private def productOrSumSymbols[T: Type](using quotes: Quotes): Seq[quotes.reflect.Symbol] = { + import quotes.reflect.* + val tpe = TypeRepr.of[T] + + tpe.classSymbol match { + case Some(clazzSym) if clazzSym.flags.is(Flags.Case) => + clazzSym.primaryConstructor.paramSymss.find(_.headOption.fold(false)(_.isTerm)).getOrElse(Nil) + + case Some(maybeSum) => + Expr.summon[Mirror.Of[T]] match { + case Some('{$m: mt { type MirroredElemTypes = met}}) => + + def extractTupleTypes(tpe: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tpe match { + case AppliedType(_, List(x: TypeRepr, xs: TypeRepr)) => extractTupleTypes(xs, x :: acc) + case _ => acc.reverse + } + + extractTupleTypes(TypeRepr.of[met], Nil).map(_.typeSymbol) + + case _ => + report.errorAndAbort(s"No Mirror found for ${tpe.show}") + } + + case None => + report.errorAndAbort(s"${tpe.show} is not case class or the root of a sealed family of types") + } + } + + def allAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[Annotations[A, T]] = { + import quotes.reflect.* + errorIfInvalidAnnotation[A] + + val annotations = productOrSumSymbols[T].map { symbol => + findAnnotation[A](symbol) match { + case Some(expr) =>'{Some($expr)} + case None => '{None} + } + } + + listExprToResult[HNil, Annotations[A, T]]('{HNil: HNil}, annotations.reverse) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new Annotations[A, T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + } + } + + def allTypeAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[TypeAnnotations[A, T]] = { + import quotes.reflect.* + errorIfInvalidAnnotation[A] + ??? + } + + def allAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllAnnotations[T]] = { + import quotes.reflect.* + + val annotationLists = productOrSumSymbols[T].map { symbol => + listExprToHList(symbol.annotations.map(_.asExpr)) + } + listExprToResult[HNil, AllAnnotations[T]]('{HNil: HNil}, annotationLists.reverse) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new AllAnnotations[T] { + override type Out = Acc + override def apply(): Out = $acc + } + } + } + } + + def allTypeAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllTypeAnnotations[T]] = { + import quotes.reflect.* + ??? + } } diff --git a/core/src/main/scala-3/shapeless/versionspecifics.scala b/core/src/main/scala-3/shapeless/versionspecifics.scala index 9c36ec6f9..721528358 100644 --- a/core/src/main/scala-3/shapeless/versionspecifics.scala +++ b/core/src/main/scala-3/shapeless/versionspecifics.scala @@ -16,6 +16,20 @@ package shapeless +import scala.quoted.* + trait ScalaVersionSpecifics { def cachedImplicit[T]: T = ??? } + +private[shapeless] def listExprToResult[Acc <: HList: Type, Out](acc: Expr[Acc], rest: Seq[Expr[Any]])( + makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] +)(using Quotes): Expr[Out] = + rest match { + case Nil => makeResult(acc) + case Seq('{$head: tpe}, tail*) => + listExprToResult('{new ::($head, $acc)}, tail)(makeResult) + } + +private[shapeless] def listExprToHList(list: Seq[Expr[Any]])(using Quotes): Expr[HList] = + listExprToResult[HNil, HList]('{HNil: HNil}, list)([Acc <: HList] => (tpe: Type[Acc]) ?=> (expr: Expr[Acc]) => expr) From 6542a4c73fd8df191254dbbf695c7831c939c593 Mon Sep 17 00:00:00 2001 From: Katrix Date: Tue, 3 Aug 2021 23:21:25 +0200 Subject: [PATCH 27/32] Fix ambigous =:!= and <:!< --- core/src/main/scala-2/shapeless/versionspecifics.scala | 8 ++++++++ core/src/main/scala-3/shapeless/versionspecifics.scala | 5 +++++ core/src/main/scala/shapeless/package.scala | 8 -------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/src/main/scala-2/shapeless/versionspecifics.scala b/core/src/main/scala-2/shapeless/versionspecifics.scala index c0851c6c6..9c9b3217b 100644 --- a/core/src/main/scala-2/shapeless/versionspecifics.scala +++ b/core/src/main/scala-2/shapeless/versionspecifics.scala @@ -20,6 +20,14 @@ import scala.language.experimental.macros import scala.reflect.macros.whitebox trait ScalaVersionSpecifics { + implicit def neq[A, B] : A =:!= B = new =:!=[A, B] {} + implicit def neqAmbig1[A] : A =:!= A = unexpected + implicit def neqAmbig2[A] : A =:!= A = unexpected + + implicit def nsub[A, B] : A <:!< B = new <:!<[A, B] {} + implicit def nsubAmbig1[A, B >: A] : A <:!< B = unexpected + implicit def nsubAmbig2[A, B >: A] : A <:!< B = unexpected + private[shapeless] def implicitNotFoundMessage(c: whitebox.Context)(tpe: c.Type): String = { val global = c.universe.asInstanceOf[scala.tools.nsc.Global] val gTpe = tpe.asInstanceOf[global.Type] diff --git a/core/src/main/scala-3/shapeless/versionspecifics.scala b/core/src/main/scala-3/shapeless/versionspecifics.scala index 721528358..525a0f0d8 100644 --- a/core/src/main/scala-3/shapeless/versionspecifics.scala +++ b/core/src/main/scala-3/shapeless/versionspecifics.scala @@ -17,8 +17,13 @@ package shapeless import scala.quoted.* +import scala.util.NotGiven trait ScalaVersionSpecifics { + given [A, B](using NotGiven[A =:= B]): =:!=[A, B] = new =:!=[A, B] {} + + given [A, B](using NotGiven[A <:< B]): <:!<[A, B] = new <:!<[A, B] {} + def cachedImplicit[T]: T = ??? } diff --git a/core/src/main/scala/shapeless/package.scala b/core/src/main/scala/shapeless/package.scala index 5de8ced95..e8dbe9358 100644 --- a/core/src/main/scala/shapeless/package.scala +++ b/core/src/main/scala/shapeless/package.scala @@ -36,17 +36,9 @@ package object shapeless extends ScalaVersionSpecifics { // Type inequalities trait =:!=[A, B] extends Serializable - implicit def neq[A, B] : A =:!= B = new =:!=[A, B] {} - implicit def neqAmbig1[A] : A =:!= A = unexpected - implicit def neqAmbig2[A] : A =:!= A = unexpected - @scala.annotation.implicitNotFound("${A} must not be a subtype of ${B}") trait <:!<[A, B] extends Serializable - implicit def nsub[A, B] : A <:!< B = new <:!<[A, B] {} - implicit def nsubAmbig1[A, B >: A] : A <:!< B = unexpected - implicit def nsubAmbig2[A, B >: A] : A <:!< B = unexpected - // Type-lambda for context bound type |¬|[T] = { type λ[U] = U <:!< T From 269c7133758ec7937f49be8613867cb0b2256c52 Mon Sep 17 00:00:00 2001 From: Katrix Date: Wed, 4 Aug 2021 17:00:53 +0200 Subject: [PATCH 28/32] Fix most tests and examples on the Scala 2 side --- build.sbt | 2 +- .../test/scala/shapeless/serialization.scala | 76 ++-- .../shapeless/serializationtestutils.scala | 0 .../src/test/scala_2.13-/shapeless/lazy.scala | 120 ------- .../shapeless/serializationtestutils.scala | 39 --- .../src/main/scala-2/shapeless/generic1.scala | 8 +- core/src/main/scala-2/shapeless/nat.scala | 36 +- .../main/scala-3/shapeless/coproduct.scala | 8 +- core/src/main/scala-3/shapeless/generic.scala | 12 +- .../src/main/scala-3/shapeless/generic1.scala | 8 +- core/src/main/scala-3/shapeless/nat.scala | 31 ++ .../scala-3/shapeless/test/illTyped.scala | 37 ++ .../main/scala-3/shapeless/test/types.scala | 13 + core/src/main/scala/shapeless/generic1.scala | 10 +- core/src/main/scala/shapeless/lenses.scala | 4 +- core/src/main/scala/shapeless/nat.scala | 23 ++ .../main/scala/shapeless/ops/records.scala | 2 +- .../main/scala/shapeless/syntax/hlists.scala | 4 +- .../main/scala/shapeless/syntax/records.scala | 25 +- .../scala/shapeless/syntax/std/tuples.scala | 4 +- .../shapeless/compiletime.scala | 0 .../shapeless/LabelledGenericTests213.scala | 2 +- core/src/test/scala/shapeless/alacarte.scala | 100 ------ .../src/test/scala/shapeless/annotation.scala | 2 +- core/src/test/scala/shapeless/coproduct.scala | 56 ++- core/src/test/scala/shapeless/default.scala | 25 +- core/src/test/scala/shapeless/generic.scala | 56 ++- core/src/test/scala/shapeless/hlist.scala | 299 ++-------------- core/src/test/scala/shapeless/hmap.scala | 6 +- core/src/test/scala/shapeless/implicits.scala | 6 +- .../scala/shapeless/labelledgeneric.scala | 21 +- core/src/test/scala/shapeless/lazy.scala | 327 ------------------ core/src/test/scala/shapeless/lenses.scala | 4 +- core/src/test/scala/shapeless/monoid.scala | 4 +- core/src/test/scala/shapeless/poly.scala | 46 +-- core/src/test/scala/shapeless/product.scala | 5 +- core/src/test/scala/shapeless/records.scala | 170 +++------ .../src/test/scala/shapeless/singletons.scala | 104 ++---- core/src/test/scala/shapeless/sybclass.scala | 40 +-- core/src/test/scala/shapeless/tuples.scala | 37 +- core/src/test/scala/shapeless/typeable.scala | 1 + .../test/scala/shapeless/typeoperators.scala | 88 +---- core/src/test/scala/shapeless/unions.scala | 58 ++-- core/src/test/scala/shapeless/unwrapped.scala | 6 +- .../scala/shapeless/examples/alacache.scala | 61 ++-- .../scala/shapeless/examples/alacarte.scala | 14 - .../shapeless/examples/backtracking.scala | 20 +- .../scala/shapeless/examples/basecopy.scala | 164 --------- .../shapeless/examples/boolinduction.scala | 26 +- .../shapeless/examples/cartesianproduct.scala | 10 +- .../scala/shapeless/examples/derivation.scala | 8 +- .../main/scala/shapeless/examples/enum.scala | 4 +- .../scala/shapeless/examples/factorial.scala | 2 +- .../scala/shapeless/examples/fibonacci.scala | 12 +- .../scala/shapeless/examples/fizzbuzz.scala | 8 +- .../scala/shapeless/examples/flatten.scala | 8 +- .../main/scala/shapeless/examples/fold.scala | 4 +- .../main/scala/shapeless/examples/gcd.scala | 2 +- .../shapeless/examples/labelledgeneric.scala | 5 +- .../shapeless/examples/linearalgebra.scala | 2 +- .../scala/shapeless/examples/newtype.scala | 2 +- .../main/scala/shapeless/examples/pack.scala | 6 +- .../scala/shapeless/examples/parsing.scala | 6 +- .../shapeless/examples/recordsubtyping.scala | 13 +- .../shapeless/examples/recursionschemes.scala | 2 +- .../main/scala/shapeless/examples/sexp.scala | 8 +- .../main/scala/shapeless/examples/shows.scala | 6 +- .../scala/shapeless/examples/sorting.scala | 14 +- .../scala/shapeless/examples/staging.scala | 4 +- .../scala/shapeless/examples/unfold.scala | 16 +- .../scala/shapeless/examples/unwrapped.scala | 8 +- .../scala/shapeless/examples/zipapply.scala | 2 +- 72 files changed, 642 insertions(+), 1720 deletions(-) rename core/jvm/src/test/{scala_2.13+ => scala}/shapeless/serializationtestutils.scala (100%) delete mode 100644 core/jvm/src/test/scala_2.13-/shapeless/lazy.scala delete mode 100644 core/jvm/src/test/scala_2.13-/shapeless/serializationtestutils.scala create mode 100644 core/src/main/scala-3/shapeless/test/illTyped.scala create mode 100644 core/src/main/scala-3/shapeless/test/types.scala rename core/src/test/{scala => scala-2}/shapeless/compiletime.scala (100%) rename core/src/test/{scala_2.13+ => scala}/shapeless/LabelledGenericTests213.scala (78%) delete mode 100644 core/src/test/scala/shapeless/alacarte.scala delete mode 100644 core/src/test/scala/shapeless/lazy.scala delete mode 100644 examples/src/main/scala/shapeless/examples/basecopy.scala diff --git a/build.sbt b/build.sbt index e8959bb79..163b5874f 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject val Scala213 = "2.13.6" -val Scala3 = "3.0.3-RC1-bin-20210801-2191757-NIGHTLY" +val Scala3 = "3.0.3-RC1-bin-20210803-010f8de-NIGHTLY" commonSettings noPublishSettings diff --git a/core/jvm/src/test/scala/shapeless/serialization.scala b/core/jvm/src/test/scala/shapeless/serialization.scala index 8120668b4..1a81cf64e 100644 --- a/core/jvm/src/test/scala/shapeless/serialization.scala +++ b/core/jvm/src/test/scala/shapeless/serialization.scala @@ -110,42 +110,42 @@ object SerializationTestDefns { } object combineL extends Poly2 { - implicit def ci = at[Int, Int]((acc, i) => acc+i) - implicit def cs = at[Int, String]((acc, s) => acc+s.length) - implicit def cb = at[Int, Boolean]((acc, b) => acc+(if(b) 1 else 0)) + implicit def ci: Case.Aux[Int, Int, Int] = at[Int, Int]((acc, i) => acc+i) + implicit def cs: Case.Aux[Int, String, Int] = at[Int, String]((acc, s) => acc+s.length) + implicit def cb: Case.Aux[Int, Boolean, Int] = at[Int, Boolean]((acc, b) => acc+(if(b) 1 else 0)) } object combineR extends Poly2 { - implicit def ci = at[Int, Int]((i, acc) => acc+i) - implicit def cs = at[String, Int]((s, acc) => acc+s.length) - implicit def cb = at[Boolean, Int]((b, acc) => acc+(if(b) 1 else 0)) + implicit def ci: Case.Aux[Int, Int, Int] = at[Int, Int]((i, acc) => acc+i) + implicit def cs: Case.Aux[String, Int, Int] = at[String, Int]((s, acc) => acc+s.length) + implicit def cb: Case.Aux[Boolean, Int, Int] = at[Boolean, Int]((b, acc) => acc+(if(b) 1 else 0)) } object selInt extends Poly1 { - implicit def ci = at[Int] { x => x } + implicit def ci: Case.Aux[Int, Int] = at[Int] { x => x } } object smear extends Poly { - implicit val caseIntInt = use((x: Int, y: Int) => x + y) - implicit val caseStringInt = use((x: String, y: Int) => x.toInt + y) - implicit val caseIntString = use((x: Int, y: String) => x + y.toInt) + implicit val caseIntInt: ProductCase.Aux[Int :: Int :: HNil, Int] = use((x: Int, y: Int) => x + y) + implicit val caseStringInt: ProductCase.Aux[String :: Int :: HNil, Int] = use((x: String, y: Int) => x.toInt + y) + implicit val caseIntString: ProductCase.Aux[Int :: String :: HNil, Int] = use((x: Int, y: String) => x + y.toInt) } object coIdentity extends Poly1 { - implicit def default[A] = at[A](a => Coproduct[A :+: CNil](a)) + implicit def default[A]: Case.Aux[A, A :+: CNil] = at[A](a => Coproduct[A :+: CNil](a)) } object gsize extends Poly1 { - implicit def caseInt = at[Int](_ => 1) - implicit def caseString = at[String](_.length) - implicit def default[T] = at[T](_ => 1) + implicit def caseInt: Case.Aux[Int, Int] = at[Int](_ => 1) + implicit def caseString: Case.Aux[String, Int] = at[String](_.length) + implicit def default[T]: Case.Aux[T, Int] = at[T](_ => 1) } object plus extends Poly2 { - implicit val caseInt = at[Int, Int](_ + _) - implicit val caseDouble = at[Double, Double](_ + _) - implicit val caseString = at[String, String](_ + _) - implicit def caseList[T] = at[List[T], List[T]](_ ::: _) + implicit val caseInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) + implicit val caseDouble: Case.Aux[Double, Double, Double] = at[Double, Double](_ + _) + implicit val caseString: Case.Aux[String, String, String] = at[String, String](_ + _) + implicit def caseList[T]: Case.Aux[List[T], List[T], List[T]] = at[List[T], List[T]](_ ::: _) } trait Quux @@ -170,15 +170,15 @@ object SerializationTestDefns { case class Box[T](t: T) - type K = HList.`"a", "b", "c"`.T - type R = Record.`"a" -> Int, "b" -> String, "c" -> Boolean`.T - type U = Union.`"a" -> Int, "b" -> String, "c" -> Boolean`.T - type RM = Record.`"c" -> Boolean, "d" -> Double`.T - type RM1 = Record.`"c" -> Boolean, "b" -> String`.T - type RM2 = Record.`"b" -> String, "c" -> Boolean`.T - type KA = Witness.`"a"`.T - type KB = Witness.`"b"`.T - type KC = Witness.`"c"`.T + type K = "a" :: "b" :: "c" :: HNil + type R = ("a" ->> Int) :: ("b" ->> String) :: ("c" ->> Boolean) :: HNil + type U = ("a" ->> Int) :+: ("b" ->> String) :+: ("c" ->> Boolean) :+: CNil + type RM = ("c" ->> Boolean) :: ("d" ->> Double) :: HNil + type RM1 = ("c" ->> Boolean) :: ("b" ->> String) :: HNil + type RM2 = ("b" ->> String) :: ("c" ->> Boolean) :: HNil + type KA = "a" + type KB = "b" + type KC = "c" sealed trait Tree[T] case class Leaf[T](t: T) extends Tree[T] @@ -314,7 +314,7 @@ class SerializationTests { val r = "foo" ->> 23 :: "bar" ->> "foo" :: "baz" ->> true :: HNil - type U = Union.`"foo" -> Int, "bar" -> String, "baz" -> Boolean`.T + type U = ("foo" ->> Int) :+: ("bar" ->> String) :+: ("baz" ->> Boolean) :+: CNil val u = Union[U](bar = "quux") val t = (23, "foo", true) @@ -355,8 +355,7 @@ class SerializationTests { type LT = (Int, String) :: (Boolean, Double) :: (Char, Float) :: HNil type AL = (Int => Double) :: (String => Char) :: (Boolean => Float) :: HNil type I3 = Int :: Int :: Int :: HNil - val s = HList.`"a", "boo", 23, true` - type S = s.T + type S = "a" :: "boo" :: 23 :: true :: HNil assertSerializable(IsHCons[L]) @@ -616,8 +615,7 @@ class SerializationTests { type L = Int :+: String :+: Boolean :+: CNil type LP = String :+: Boolean :+: Int :+: CNil type BS = Boolean :+: String :+: CNil - val s = Coproduct.`"a", "boo", 23, true` - type S = s.T + type S = "a" :+: "boo" :+: 23 :+: true :+: CNil assertSerializable(Inject[L, Int]) assertSerializable(Inject[L, String]) @@ -978,8 +976,8 @@ class SerializationTests { assertSerializable(Typeable[Double]) assertSerializable(Typeable[String]) assertSerializable(Typeable[Foo]) - assertSerializable(Typeable[Witness.`3`.T]) - assertSerializable(Typeable[Witness.`"foo"`.T]) + assertSerializable(Typeable[3]) + assertSerializable(Typeable["foo"]) // in general, referenceSingletonTypeables // shouldn't be serializable, since they @@ -990,13 +988,13 @@ class SerializationTests { // special cases of referenceSingletonTypeable, // because symbols and objects preserve their // identity during serialization/deserialization: - assertSerializable(Typeable[Witness.`"foo"`.T]) + assertSerializable(Typeable["foo"]) assertSerializable(Typeable[Sing.type]) assertSerializable(Typeable[CaseObj.type]) // check that they indeed work // correctly after deserialization: - val symInst = roundtrip(Typeable[Witness.`"foo"`.T]) + val symInst = roundtrip(Typeable["foo"]) assertTrue(symInst.cast("foo": Any).isDefined) val objInst = roundtrip(Typeable[Sing.type]) assertTrue(objInst.cast(Sing: Any).isDefined) @@ -1103,8 +1101,8 @@ class SerializationTests { type OL = Option[Int] :: Option[String] :: Option[Boolean] :: HNil type I3 = Int :: Int :: Int :: HNil type IS = Int :: String :: HNil - type R = Record.`"a" -> Int, "b" -> String, "c" -> Boolean`.T - type K = HList.`"a", "b", "c"`.T + type R = ("a" ->> Int) :: ("b" ->> String) :: ("c" ->> Boolean) :: HNil + type K = "a" :: "b" :: "c" :: HNil assertSerializable(UnaryTCConstraint[HNil, Option]) assertSerializable(UnaryTCConstraint[OL, Option]) @@ -1181,7 +1179,7 @@ class SerializationTests { val l8 = optic.hlistSelectLens[Int :: String :: Boolean :: HNil, String] val l9 = optic.coproductSelectPrism[Int :+: String :+: Boolean :+: CNil, String] val l10 = optic.hlistNthLens[Int :: String :: Boolean :: HNil, _1] - val l11 = optic.recordLens[Record.`"foo" -> Int, "bar" -> String, "baz" -> Boolean`.T]("bar") + val l11 = optic.recordLens[("foo" ->> Int) :: ("bar" ->> String) :: ("baz" ->> Boolean) :: HNil, "bar"]("bar") val l12 = optic[Tree[Int]].l.r.l.t val l13 = optic[Node[Int]] >> "r" val l14 = optic[Node[Int]] >> _1 diff --git a/core/jvm/src/test/scala_2.13+/shapeless/serializationtestutils.scala b/core/jvm/src/test/scala/shapeless/serializationtestutils.scala similarity index 100% rename from core/jvm/src/test/scala_2.13+/shapeless/serializationtestutils.scala rename to core/jvm/src/test/scala/shapeless/serializationtestutils.scala diff --git a/core/jvm/src/test/scala_2.13-/shapeless/lazy.scala b/core/jvm/src/test/scala_2.13-/shapeless/lazy.scala deleted file mode 100644 index c4733cde1..000000000 --- a/core/jvm/src/test/scala_2.13-/shapeless/lazy.scala +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2013-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.language.reflectiveCalls - -import org.junit.Test -import org.junit.Assert._ - -class LazyStrictTestsJVM { - - case class CC(l: List[CC]) - - trait TC[T] { - def repr(depth: Int): String - } - - object TC { - def apply[T](implicit tc: TC[T]): TC[T] = tc - - def instance[T](repr0: Int => String): TC[T] = - new TC[T] { - def repr(depth: Int) = - if (depth < 0) - "…" - else - repr0(depth) - } - } - - object TC0 extends TCImplicits[Lazy, Strict, Strict] - object TC1 extends TCImplicits[Strict, Lazy, Strict] - object TC2 extends TCImplicits[Strict, Strict, Lazy ] - object TC3 extends TCImplicits[Strict, Strict, Strict] - - trait TCImplicits[A[T] <: { def value: T }, B[T] <: { def value: T }, C[T] <: { def value: T }] { - implicit def listTC[T](implicit underlying: A[TC[T]]): TC[List[T]] = - TC.instance(depth => s"List(${underlying.value.repr(depth - 1)})") - - implicit def hnilTC: TC[HNil] = - TC.instance(_ => "HNil") - - implicit def hconsTC[H, T <: HList] - (implicit - headTC: B[TC[H]], - tailTC: TC[T] - ): TC[H :: T] = - TC.instance(depth => s"${headTC.value.repr(depth - 1)} :: ${tailTC.repr(depth)}") - - implicit def genericTC[F, G] - (implicit - gen: Generic.Aux[F, G], - underlying: C[TC[G]] - ): TC[F] = - TC.instance(depth => s"Generic(${underlying.value.repr(depth - 1)})") - } - - /** Illustrates that a single `Lazy` is enough to break a cycle */ - @Test - def testCycle: Unit = { - val (ccTC0, genTC0, listTC0) = { - import TC0._ - (TC[CC], TC[List[CC] :: HNil], TC[List[CC]]) - } - - val (ccTC1, genTC1, listTC1) = { - import TC1._ - (TC[CC], TC[List[CC] :: HNil], TC[List[CC]]) - } - - val (ccTC2, genTC2, listTC2) = { - import TC2._ - (TC[CC], TC[List[CC] :: HNil], TC[List[CC]]) - } - - val (ccTC3SO, genTC3SO, listTC3SO) = { - import TC3._ - def throwsStackOverflow[T](f: => T): Boolean = - try { f; false } - catch { case _: StackOverflowError => true } - - (throwsStackOverflow(TC[CC]), throwsStackOverflow(TC[List[CC] :: HNil]), throwsStackOverflow(TC[List[CC]])) - } - - val expectedCCRepr = "Generic(List(Generic(List(Generic(… :: HNil)) :: HNil)) :: HNil)" - val expectedGenRepr = "List(Generic(List(Generic(List(…) :: HNil)) :: HNil)) :: HNil" - val expectedListRepr = "List(Generic(List(Generic(List(Generic(…)) :: HNil)) :: HNil))" - - assert(ccTC0.repr(7) == expectedCCRepr) - assert(genTC0.repr(7) == expectedGenRepr) - assert(listTC0.repr(7) == expectedListRepr) - - assert(ccTC1.repr(7) == expectedCCRepr) - assert(genTC1.repr(7) == expectedGenRepr) - assert(listTC1.repr(7) == expectedListRepr) - - assert(ccTC2.repr(7) == expectedCCRepr) - assert(genTC2.repr(7) == expectedGenRepr) - assert(listTC2.repr(7) == expectedListRepr) - - assert(ccTC3SO) - assert(genTC3SO) - assert(listTC3SO) - } -} - diff --git a/core/jvm/src/test/scala_2.13-/shapeless/serializationtestutils.scala b/core/jvm/src/test/scala_2.13-/shapeless/serializationtestutils.scala deleted file mode 100644 index d989631cc..000000000 --- a/core/jvm/src/test/scala_2.13-/shapeless/serializationtestutils.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.collection.GenTraversableLike -import scala.collection.generic.{ CanBuildFrom, IsTraversableLike } - -object serializationtestutils { - /** - * A `CanBuildFrom` for `List` implementing `Serializable`, unlike the one provided by the standard library. - */ - implicit def listSerializableCanBuildFrom[T]: CanBuildFrom[List[T], T, List[T]] = - new CanBuildFrom[List[T], T, List[T]] with Serializable { - def apply(from: List[T]) = from.genericBuilder[T] - def apply() = List.newBuilder[T] - } - - // To satisfy serialization of `ToSizedHList` we must provide a serializable `IsTraversableLike` - //implicit val listIntSerializableIsTraversableLike: IsTraversableLike[List[Int]] { type A = Int } = null - implicit def listSerializableIsIterableLike[T]: IsTraversableLike[List[T]] { type A = T } = - new IsTraversableLike[List[T]] with Serializable { - type A = T - val conversion: List[T] => GenTraversableLike[T, List[T]] = identity - } -} diff --git a/core/src/main/scala-2/shapeless/generic1.scala b/core/src/main/scala-2/shapeless/generic1.scala index 460119d71..8d1bb3dd1 100644 --- a/core/src/main/scala-2/shapeless/generic1.scala +++ b/core/src/main/scala-2/shapeless/generic1.scala @@ -19,7 +19,7 @@ package shapeless import scala.language.experimental.macros import scala.reflect.macros.whitebox -trait Generic1ScalaCompat { +trait Generic1ScalaCompat extends Generic10 { implicit def mkGeneric10[T[_], U[_], FR[_[_], _[_]]]: Generic1[T, ({ type λ[t[_]] = FR[t, U] })#λ] = macro Generic1Macros.mkGeneric1Impl[T, ({ type λ[t[_]] = FR[t, U] })#λ] @@ -32,7 +32,7 @@ trait Generic10ScalaCompat { implicit def apply[T[_], FR[_[_]]]: Generic1[T, FR] = macro Generic1Macros.mkGeneric1Impl[T, FR] } -trait IsHCons1ScalaCompat { +trait IsHCons1ScalaCompat extends IsHCons10 { implicit def mkIsHCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsHCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = macro IsHCons1Macros.mkIsHCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] @@ -51,7 +51,7 @@ trait IsHCons10ScalaCompat { implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsHCons1[L, FH, FT] = macro IsHCons1Macros.mkIsHCons1Impl[L, FH, FT] } -trait IsCCons1ScalaCompat { +trait IsCCons1ScalaCompat extends IsCCons10 { implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]: IsCCons1[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] = macro IsCCons1Macros.mkIsCCons1Impl[L, ({ type λ[t[_]] = FH[t, U] })#λ, FT] @@ -70,7 +70,7 @@ trait IsCCons10ScalaCompat { implicit def apply[L[_], FH[_[_]], FT[_[_]]]: IsCCons1[L, FH, FT] = macro IsCCons1Macros.mkIsCCons1Impl[L, FH, FT] } -trait Split1ScalaCompat { +trait Split1ScalaCompat extends Split10 { implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] = macro Split1Macros.mkSplit1Impl[L, ({ type λ[t[_]] = FO[t, U] })#λ, FI] diff --git a/core/src/main/scala-2/shapeless/nat.scala b/core/src/main/scala-2/shapeless/nat.scala index 1131866ba..799f8a8be 100644 --- a/core/src/main/scala-2/shapeless/nat.scala +++ b/core/src/main/scala-2/shapeless/nat.scala @@ -24,7 +24,11 @@ trait NatScalaCompat { implicit def apply(i: Int): Nat = macro NatMacros.materializeWidened } -class NatMacros(val c: whitebox.Context) extends NatMacroDefns { +trait NatWithTypeAtPosScalaCompat { + implicit def fromInt[L](i: Int): NatWithTypeAtPos[L] = macro NatMacros.makeNatWithTypeAtPos[L] +} + +class NatMacros(val c: whitebox.Context) extends NatMacroDefns with CaseClassMacros { import c.universe._ def materializeWidened(i: Tree): Tree = @@ -33,6 +37,36 @@ class NatMacros(val c: whitebox.Context) extends NatMacroDefns { case _ => c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") } + + def makeNatWithTypeAtPos[L: WeakTypeTag](i: Tree): Tree = { + i match { + case NatLiteral(n) => + val L = weakTypeOf[L].dealias + val N = mkNatTpt(n) + + val elements = if(L <:< hlistTpe) { + unpackHList(L) + } else if (isTuple(L)) { + fieldsOf(L).map(_._2) + } else { + c.abort(c.enclosingPosition, s"The list $L must be either an HList or a tuple") + } + + if (n >= elements.length) { + c.abort(c.enclosingPosition, s"The list $L is too short to have an element at index $n") + } + + val Out = elements(n) + + q"""new _root_.shapeless.NatWithTypeAtPos[$L] { + type N = $N + type Tpe = $Out + val value: $N = ${mkNatValue(n)} + }""" + case _ => + c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal") + } + } } trait NatMacroDefns { diff --git a/core/src/main/scala-3/shapeless/coproduct.scala b/core/src/main/scala-3/shapeless/coproduct.scala index 4a31c5525..e961b8924 100644 --- a/core/src/main/scala-3/shapeless/coproduct.scala +++ b/core/src/main/scala-3/shapeless/coproduct.scala @@ -17,12 +17,12 @@ trait CoproductScalaCompat { } def extractCoproduct[C <: Coproduct](coproduct: C): scala.Tuple.Union[CoproductToTuple[C]] = coproduct match { - case Inl(head) => head.asInstanceOf - case Inr(tail) => extractCoproduct(tail.asInstanceOf) + case Inl(head) => head.asInstanceOf[scala.Tuple.Union[CoproductToTuple[C]]] + case Inr(tail) => extractCoproduct(tail.asInstanceOf[C]) case err: CNil => err.impossible } def coproductFromOrdinal[T <: scala.Tuple](a: scala.Tuple.Union[T], ordinal: Int): TupleToCoproduct[T] = - if ordinal == 0 then Inl(a).asInstanceOf - else Inr(coproductFromOrdinal(a, ordinal - 1)).asInstanceOf + if ordinal == 0 then Inl(a).asInstanceOf[TupleToCoproduct[T]] + else Inr(coproductFromOrdinal(a, ordinal - 1)).asInstanceOf[TupleToCoproduct[T]] } diff --git a/core/src/main/scala-3/shapeless/generic.scala b/core/src/main/scala-3/shapeless/generic.scala index 07a590dd4..92a823454 100644 --- a/core/src/main/scala-3/shapeless/generic.scala +++ b/core/src/main/scala-3/shapeless/generic.scala @@ -20,7 +20,15 @@ import scala.deriving._ trait GenericScalaCompat { - given materializeProduct[T <: Product]( + given Generic.Aux[Unit, Unit :: HNil] = new Generic[Unit] { + override type Repr = Unit :: HNil + + override def to(t: Unit): Repr = t :: HNil + + override def from(r: Repr): Unit = r.head + } + + transparent inline given materializeProduct[T <: Product]( using m: scala.deriving.Mirror.ProductOf[T] ): Generic.Aux[T, HList.TupleToHList[m.MirroredElemTypes]] = new Generic[T] { @@ -31,7 +39,7 @@ trait GenericScalaCompat { override def from(r: Repr): T = m.fromProduct(HList.hListToTuple(r)) } - given materializeSum[T]( + transparent inline given materializeSum[T]( using m: scala.deriving.Mirror.SumOf[T], ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, ): Generic.Aux[T, Coproduct.TupleToCoproduct[m.MirroredElemTypes]] = diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index b5e312120..522da3b9e 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -39,7 +39,7 @@ type MirrorOf1Sum[A[_]] = Mirror.Sum { type MirroredElemTypes[Z] <: scala.Tuple } -trait Generic1ScalaCompat { +trait Generic1ScalaCompat extends Generic10{ given mkGeneric10Product[T[_] <: Product, U[_], FR[_[_], _[_]]]( using m: MirrorOf1Product[T], @@ -111,7 +111,7 @@ type HeadElemTypes[ElemTypes[_] <: scala.Tuple] = [Z] =>> Head[ElemTypes[Z]] type TailElemTypesHCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> HList.TupleToHList[Tail[ElemTypes[Z]]] -trait IsHCons1ScalaCompat { +trait IsHCons1ScalaCompat extends IsHCons10 { given mkIsHCons10[L[_] <: Product, FH[_[_], _[_]], U[_], FT[_[_]]]( using m: MirrorOf1Product[L], @@ -169,7 +169,7 @@ trait IsHCons10ScalaCompat { type TailElemTypesCCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> Coproduct.TupleToCoproduct[Tail[ElemTypes[Z]]] -trait IsCCons1ScalaCompat { +trait IsCCons1ScalaCompat extends IsCCons10 { implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]( using m: MirrorOf1Sum[L], @@ -227,7 +227,7 @@ trait IsCCons10ScalaCompat { } } -trait Split1ScalaCompat { +trait Split1ScalaCompat extends Split10 { implicit def mkSplit10[L[_], FO[_[_], _[_]], U[_], FI[_[_]]]: Split1[L, Apply10[FO, U], FI] = ??? diff --git a/core/src/main/scala-3/shapeless/nat.scala b/core/src/main/scala-3/shapeless/nat.scala index 767747dc7..de0779293 100644 --- a/core/src/main/scala-3/shapeless/nat.scala +++ b/core/src/main/scala-3/shapeless/nat.scala @@ -35,3 +35,34 @@ trait NatScalaCompat { else if i == 0 then (new _0).asInstanceOf[IntToNat[i.type]] else (new Succ).asInstanceOf[IntToNat[i.type]] } + +trait NatWithTypeAtPosScalaCompat { + + //Transparent gives better types here + transparent inline implicit def fromIntList[L <: HList, Out](inline i: Int)(implicit at: ops.hlist.At.Aux[L, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[L] = + if i < 0 then compiletime.error("Can't convert value less than 0 to nat") + else { + type N0 = Nat.IntToNat[i.type] + val n = Nat(i) + + new NatWithTypeAtPos[L] { + type N = N0 + type Tpe = Out + val value: N = n.asInstanceOf[N] + } + } + + //Transparent gives better types here + transparent inline implicit def fromIntTuple[T <: scala.Tuple, Out](inline i: Int)(implicit at: ops.tuple.At.Aux[T, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[T] = + if i < 0 then compiletime.error("Can't convert value less than 0 to nat") + else { + type N0 = Nat.IntToNat[i.type] + val n = Nat(i) + + new NatWithTypeAtPos[T] { + type N = N0 + type Tpe = Out + val value: N = n.asInstanceOf[N] + } + } +} diff --git a/core/src/main/scala-3/shapeless/test/illTyped.scala b/core/src/main/scala-3/shapeless/test/illTyped.scala new file mode 100644 index 000000000..ab64fc6fd --- /dev/null +++ b/core/src/main/scala-3/shapeless/test/illTyped.scala @@ -0,0 +1,37 @@ +package shapeless.test + +import java.util.regex.Pattern +import scala.compiletime.* +import scala.compiletime.testing.* + +object illTyped { + inline def apply(inline code: String): Unit = { + val errors = typeCheckErrors(code) + + errors.find(_.kind == ErrorKind.Parser).foreach { e => + error(s"Parsing failed.\n${e.message}") + } + + if (errors.isEmpty) { + error("Type-checking succeeded unexpectedly.\nExpected some error.") + } + } + + inline def apply(inline code: String, inline expected: String): Unit = { + val errors = typeCheckErrors(code) + + val expectedPattern: Pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) + + errors.find(_.kind == ErrorKind.Parser).foreach { e => + error(s"Parsing failed.\n${e.message}") + } + + if (errors.isEmpty) { + error("Type-checking succeeded unexpectedly.\nExpected some error.") + } + + if (!errors.exists(e => expectedPattern.matcher(e.message).matches)) { + error("Type-checking failed in an unexpected way.\n" + expected + "\nActual error: "+ errors.head.message) + } + } +} diff --git a/core/src/main/scala-3/shapeless/test/types.scala b/core/src/main/scala-3/shapeless/test/types.scala new file mode 100644 index 000000000..40c0dafd6 --- /dev/null +++ b/core/src/main/scala-3/shapeless/test/types.scala @@ -0,0 +1,13 @@ +package shapeless.test + +import scala.quoted.* + +def typed[T](t : => T): Unit = {} + +def sameTyped[T](t1: => T)(t2: => T): Unit = {} + +inline def showType[T]: String = ${showTypeImpl[T]} + +inline def showType[T](t: => T): String = ${showTypeImpl[T]} + +private def showTypeImpl[T: Type](using Quotes): Expr[String] = Expr(Type.show[T]) diff --git a/core/src/main/scala/shapeless/generic1.scala b/core/src/main/scala/shapeless/generic1.scala index dfac768fc..aac01ac46 100644 --- a/core/src/main/scala/shapeless/generic1.scala +++ b/core/src/main/scala/shapeless/generic1.scala @@ -27,9 +27,11 @@ trait Generic1[F[_], +FR[_[_]]] extends Serializable { def mkFrr: FR[R] } -object Generic1 extends Generic10 with Generic1ScalaCompat { +object Generic1 extends Generic1ScalaCompat { type Aux[F[_], +FR[_[_]], R0[_]] = Generic1[F, FR] { type R[t] = R0[t] } + def apply[T[_], FR[_[_]]](implicit gen: Generic1[T, FR]): Generic1.Aux[T, FR, gen.R] = gen + def unsafeInstance[F[_], FR[_[_]], R0[_]](f: F[Any] => R0[Any], g: R0[Any] => F[Any])(implicit lazyFr: => FR[R0]): Aux[F, FR, R0] = { new Generic1[F, FR] { type R[t] = R0[t] @@ -56,7 +58,7 @@ trait IsHCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { def mkFtt: FT[T] } -object IsHCons1 extends IsHCons10 with IsHCons1ScalaCompat { +object IsHCons1 extends IsHCons1ScalaCompat { type Aux[L[_], +FH[_[_]], +FT[_[_]], H0[_], T0[_] <: HList] = IsHCons1[L, FH, FT] { type H[t] = H0[t] ; type T[t] = T0[t] } def unsafeInstance[L[_] <: HList, FH[_[_]], FT[_[_]], H0[_], T0[_] <: HList]( @@ -91,7 +93,7 @@ trait IsCCons1[L[_], +FH[_[_]], +FT[_[_]]] extends Serializable { def mkFtt: FT[T] } -object IsCCons1 extends IsCCons10 with IsCCons1ScalaCompat { +object IsCCons1 extends IsCCons1ScalaCompat { type Aux[L[_], +FH[_[_]], +FT[_[_]], H0[_], T0[_] <: Coproduct] = IsCCons1[L, FH, FT] { type H[t] = H0[t] ; type T[t] = T0[t] } def unsafeInstance[L[_] <: Coproduct, FH[_[_]], FT[_[_]], H0[_], T0[_] <: Coproduct]( @@ -126,7 +128,7 @@ trait Split1[L[_], +FO[_[_]], +FI[_[_]]] extends Serializable { def mkFii: FI[I] } -object Split1 extends Split10 with Split1ScalaCompat { +object Split1 extends Split1ScalaCompat { type Aux[L[_], +FO[_[_]], +FI[_[_]], O0[_], I0[_]] = Split1[L, FO, FI] { type O[T] = O0[T] ; type I[T] = I0[T] } def instance[FO[_[_]], FI[_[_]], O0[_], I0[_]](implicit lazyFoo: => FO[O0], lazyFii: => FI[I0]): Aux[({ type λ[x] = O0[I0[x]] })#λ, FO, FI, O0, I0] = diff --git a/core/src/main/scala/shapeless/lenses.scala b/core/src/main/scala/shapeless/lenses.scala index b0a098fcc..94e7cadcf 100644 --- a/core/src/main/scala/shapeless/lenses.scala +++ b/core/src/main/scala/shapeless/lenses.scala @@ -39,7 +39,7 @@ trait Lens[S, A] extends LPLens[S, A] { outer => def >>(n: Nat)(implicit mkLens: MkNthFieldLens[A, n.N]): Lens[S, mkLens.Elem] = mkLens() compose this - def >>[K <: Singleton](k: K)(implicit mkLens: MkFieldLens[A, K]): Lens[S, mkLens.Elem] = mkLens() compose this + def >>[K <: String with Singleton](k: K)(implicit mkLens: MkFieldLens[A, K]): Lens[S, mkLens.Elem] = mkLens() compose this def selectDynamic(k: String)( implicit mkLens: MkSelectDynamicOptic[Lens[S, A], A, k.type, Nothing] @@ -458,7 +458,7 @@ trait MkRecordSelectLens[R <: HList, K] extends Serializable { object MkRecordSelectLens { type Aux[R <: HList, K, Elem0] = MkRecordSelectLens[R, K] { type Elem = Elem0 } - implicit def mkRecordSelectLens[R <: HList, K, E] + implicit def mkRecordSelectLens[R <: HList, K <: Singleton, E] (implicit selector: RSelector.Aux[R, K, E], updater: Updater.Aux[R, FieldType[K, E], R]): Aux[R, K, E] = new MkRecordSelectLens[R, K] { type Elem = E diff --git a/core/src/main/scala/shapeless/nat.scala b/core/src/main/scala/shapeless/nat.scala index c1a3e1031..acd341186 100644 --- a/core/src/main/scala/shapeless/nat.scala +++ b/core/src/main/scala/shapeless/nat.scala @@ -65,3 +65,26 @@ object Nat extends Nats with NatScalaCompat { implicit def valueOfZero: ValueOf[_0] = new ValueOf(_0) implicit def valueOfSucc[N <: Nat]: ValueOf[Succ[N]] = new ValueOf(Succ[N]()) } + +trait NatWithTypeAtPos[L] { + type N <: Nat + type Tpe + val value: N +} +object NatWithTypeAtPos extends NatWithTypeAtPosScalaCompat { + type Aux[L, N0 <: Nat, Tpe0] = NatWithTypeAtPos[L] { type N = N0; type Tpe = Tpe0 } + + implicit def fromNatList[L <: HList, Out](n: Nat)(implicit at: ops.hlist.At.Aux[L, n.N, Out]): NatWithTypeAtPos.Aux[L, n.N, Out] = + new NatWithTypeAtPos[L] { + type N = n.N + type Tpe = Out + val value: N = n.asInstanceOf[N] + } + + implicit def fromNatTuple[T, Out](n: Nat)(implicit at: ops.tuple.At.Aux[T, n.N, Out]): NatWithTypeAtPos.Aux[T, n.N, Out] = + new NatWithTypeAtPos[T] { + type N = n.N + type Tpe = Out + val value: N = n.asInstanceOf[N] + } +} diff --git a/core/src/main/scala/shapeless/ops/records.scala b/core/src/main/scala/shapeless/ops/records.scala index 6678dbaa1..710d3e59a 100644 --- a/core/src/main/scala/shapeless/ops/records.scala +++ b/core/src/main/scala/shapeless/ops/records.scala @@ -524,7 +524,7 @@ package record { def apply(): Out = HNil } - implicit def hlistSwapRecord[K, V, T <: HList](implicit wk: ValueOf[K], kt: SwapRecord[T]): Aux[FieldType[K, V] :: T, FieldType[V, K] :: kt.Out] = + implicit def hlistSwapRecord[K <: Singleton, V, T <: HList](implicit wk: ValueOf[K], kt: SwapRecord[T]): Aux[FieldType[K, V] :: T, FieldType[V, K] :: kt.Out] = new SwapRecord[FieldType[K, V] :: T] { type Out = FieldType[V, K] :: kt.Out def apply(): Out = field[V](wk.value) :: kt() diff --git a/core/src/main/scala/shapeless/syntax/hlists.scala b/core/src/main/scala/shapeless/syntax/hlists.scala index be63aa23f..84590f1e4 100644 --- a/core/src/main/scala/shapeless/syntax/hlists.scala +++ b/core/src/main/scala/shapeless/syntax/hlists.scala @@ -247,8 +247,8 @@ final class HListOps[L <: HList](l : L) extends Serializable { * * @author Andreas Koestler */ - def updateAtWith[N <: Nat, V, AtOut](n: N)(f: AtOut => V) - (implicit at: At.Aux[L, N, AtOut], upd: ModifierAt[L, N, AtOut, V]): upd.Out = upd(l, f) + def updateAtWith[N <: Nat, AtOut, V](n: NatWithTypeAtPos.Aux[L, N, AtOut])(f: AtOut => V)(implicit upd: ModifierAt[L, N, AtOut, V]): upd.Out = + upd(l, f) class UpdatedTypeAux[U] { def apply[V, Out <: HList](v : V) diff --git a/core/src/main/scala/shapeless/syntax/records.scala b/core/src/main/scala/shapeless/syntax/records.scala index c3ab4d25f..bcd82a838 100644 --- a/core/src/main/scala/shapeless/syntax/records.scala +++ b/core/src/main/scala/shapeless/syntax/records.scala @@ -66,15 +66,14 @@ final class RecordOps[L <: HList](val l : L) extends AnyVal with Serializable { /** * Updates a field having a value with type A by given function. */ - def updateWith[K <: Singleton, W, FSLOut](k: K)(f: FSLOut => W) - (implicit fsl: FSL[K, FSLOut], modifier: Modifier[L, K, FSLOut, W]): modifier.Out = modifier(l, f) - type FSL[K, Out] = Selector.Aux[L, K, Out] + def updateWith[K <: Singleton, FSLOut, W](k: SingletonWithTypeAtField.Aux[L, K, FSLOut])(f: FSLOut => W)(implicit modifier: Modifier[L, K, FSLOut, W]): modifier.Out = + modifier(l, f) /** * Remove the field associated with the singleton typed key k, returning both the corresponding value and the updated * record. Only available if this record has a field with keyType equal to the singleton type K. */ - def remove[K](k: ValueOf[K])(implicit remover: Remover[L, K]): remover.Out = remover(l) + def remove[K <: Singleton](k: K)(implicit remover: Remover[L, K]): remover.Out = remover(l) /** * Updates or adds to this record a field of type F. @@ -163,5 +162,21 @@ final case class DynamicRecordOps[L <: HList](l : L) extends Dynamic { /** * Allows dynamic-style access to fields of the record whose keys are Symbols. */ - def selectDynamic(key: String)(implicit selector: Selector[L, key.type]): selector.Out = selector(l) + def selectDynamic[K <: String with Singleton](key: K)(implicit selector: Selector[L, K]): selector.Out = selector(l) +} + +trait SingletonWithTypeAtField[L <: HList] { + type K <: Singleton + type Tpe + val value: K +} +object SingletonWithTypeAtField { + type Aux[L <: HList, K0 <: Singleton, Tpe0] = SingletonWithTypeAtField[L] { type K = K0; type Tpe = Tpe0 } + + implicit def fromKey[L <: HList, K0 <: Singleton, Out](k: K0)(implicit sel: ops.record.Selector.Aux[L, K0, Out]): SingletonWithTypeAtField.Aux[L, K0, Out] = + new SingletonWithTypeAtField[L] { + type K = K0 + type Tpe = Out + val value: K0 = k + } } diff --git a/core/src/main/scala/shapeless/syntax/std/tuples.scala b/core/src/main/scala/shapeless/syntax/std/tuples.scala index 5d45cd71e..d09e69e85 100644 --- a/core/src/main/scala/shapeless/syntax/std/tuples.scala +++ b/core/src/main/scala/shapeless/syntax/std/tuples.scala @@ -197,8 +197,8 @@ final class TupleOps[T](t: T) extends Serializable { * * @author Andreas Koestler */ - def updateAtWith[N <: Nat, U, AtOut](n: N)(f: AtOut => U) - (implicit at: At.Aux[T, N, AtOut], upd: ModifierAt[T, N, AtOut, U]): upd.Out = upd(t, f) + def updateAtWith[U, N <: Nat, AtOut](n: NatWithTypeAtPos.Aux[T, N, AtOut])(f: AtOut => U) + (implicit upd: ModifierAt[T, N, AtOut, U]): upd.Out = upd(t, f) class UpdatedAtAux[N <: Nat] { def apply[U, V, R](u: U)(implicit replacer: ReplaceAt.Aux[T, N, U, (V, R)]): R = replacer(t, u)._2 diff --git a/core/src/test/scala/shapeless/compiletime.scala b/core/src/test/scala-2/shapeless/compiletime.scala similarity index 100% rename from core/src/test/scala/shapeless/compiletime.scala rename to core/src/test/scala-2/shapeless/compiletime.scala diff --git a/core/src/test/scala_2.13+/shapeless/LabelledGenericTests213.scala b/core/src/test/scala/shapeless/LabelledGenericTests213.scala similarity index 78% rename from core/src/test/scala_2.13+/shapeless/LabelledGenericTests213.scala rename to core/src/test/scala/shapeless/LabelledGenericTests213.scala index 7fbe26965..147078453 100644 --- a/core/src/test/scala_2.13+/shapeless/LabelledGenericTests213.scala +++ b/core/src/test/scala/shapeless/LabelledGenericTests213.scala @@ -17,6 +17,6 @@ class LabelledGenericTests213 { object LabelledGenericTests213 { case class Hkt[F[_]](foo: F[String]) class Func[T] { - def select[R <: HList](k: Witness)(implicit gen: LabelledGeneric.Aux[T, R], selector: Selector[R, k.T]) = 0 + def select[R <: HList, K <: Singleton](k: K)(implicit gen: LabelledGeneric.Aux[T, R], selector: Selector[R, K]) = 0 } } diff --git a/core/src/test/scala/shapeless/alacarte.scala b/core/src/test/scala/shapeless/alacarte.scala deleted file mode 100644 index f79bce1b9..000000000 --- a/core/src/test/scala/shapeless/alacarte.scala +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2014 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import org.junit.Test -import org.junit.Assert._ - -import test._ - -package ALaCarteTestsAux { - object FooDefns extends DefaultCaseClassDefns { - type C = Foo - val ops = Ops - } - - object Foo extends FooDefns.CaseClassCompanion - class Foo(val i: Int, val s: String) extends FooDefns.CaseClass -} - -class ALaCarteTests { - import ALaCarteTestsAux._ - - @Test - def testApplyUnapply: Unit = { - val foo = Foo(23, "foo") - typed[Foo](foo) - - val Foo(i, s) = foo - typed[Int](i) - typed[String](s) - } - - @Test - def testProduct: Unit = { - val foo = Foo(23, "foo") - - val foo_1 = foo.productElement(0) - typed[Any](foo_1) - assertEquals(23, foo_1) - - val foo_2 = foo.productElement(1) - typed[Any](foo_2) - assertEquals("foo", foo_2) - - val fooIterator = foo.productIterator - assertEquals(List(23, "foo"), fooIterator.toList) - - val fooPrefix = foo.productPrefix - assertEquals("Foo", fooPrefix) - - val fooArity = foo.productArity - assertEquals(2, fooArity) - } - - @Test - def testPolyEquality: Unit = { - val foo = Foo(23, "foo") - val foo2 = Foo(23, "foo") - val foo3 = Foo(13, "bar") - assertEquals(foo, foo2) - assertEquals(foo.hashCode, foo2.hashCode) - assertFalse(foo == foo3) - } - - @Test - def testCopy: Unit = { - val foo = Foo(23, "foo") - val fooCopy = foo.copy() - assertFalse(fooCopy eq foo) - assertEquals(foo, fooCopy) - assertEquals(foo.hashCode, fooCopy.hashCode) - - val mod = Foo(13, "foo") - val fooMod = foo.copy(i = 13) - assertFalse(fooMod eq foo) - assertEquals(mod, fooMod) - assertEquals(mod.hashCode, fooMod.hashCode) - } - - @Test - def testToString: Unit = { - val foo = Foo(23, "foo") - val fooStr = foo.toString - assertEquals("Foo(23,foo)", fooStr) - } -} diff --git a/core/src/test/scala/shapeless/annotation.scala b/core/src/test/scala/shapeless/annotation.scala index 2ad99455f..e43e1ccf3 100644 --- a/core/src/test/scala/shapeless/annotation.scala +++ b/core/src/test/scala/shapeless/annotation.scala @@ -193,7 +193,7 @@ class AnnotationTests { def invalidTypeAnnotations: Unit = { illTyped(" TypeAnnotations[Dummy, CC2] ", "could not find implicit value for parameter annotations: .*") illTyped(" TypeAnnotations[Dummy, Base] ", "could not find implicit value for parameter annotations: .*") - illTyped(" TypeAnnotations[Second, Dummy] ", "could not find implicit value for parameter annotations: .*") + illTyped(" TypeAnnotations[Second, Dummy] ", "could not find implicit value for parameter annotations: .*") } @Test diff --git a/core/src/test/scala/shapeless/coproduct.scala b/core/src/test/scala/shapeless/coproduct.scala index d0b4881a9..ec380bc08 100644 --- a/core/src/test/scala/shapeless/coproduct.scala +++ b/core/src/test/scala/shapeless/coproduct.scala @@ -25,6 +25,7 @@ import testutil._ import ops.coproduct._ import ops.union._ import union._ +import labelled.->> class CoproductTests { type ISB = Int :+: String :+: Boolean :+: CNil @@ -42,9 +43,9 @@ class CoproductTests { type APB = Apple :+: Pear :+: Banana :+: CNil object size extends Poly1 { - implicit val caseInt = at[Int](_ => 1) - implicit val caseString = at[String](_.length) - implicit val caseBoolean = at[Boolean](_ => 1) + implicit val caseInt: Case.Aux[Int, Int] = at[Int](_ => 1) + implicit val caseString: Case.Aux[String, Int] = at[String](_.length) + implicit val caseBoolean: Case.Aux[Boolean, Int] = at[Boolean](_ => 1) } trait Dog @@ -172,7 +173,7 @@ class CoproductTests { val isd = Coproduct[I :+: S :+: D :+: CNil](1) object coIdentity extends Poly1 { - implicit def default[A] = at[A](a => Coproduct[A :+: CNil](a)) + implicit def default[A]: Case.Aux[A, A :+: CNil] = at[A](a => Coproduct[A :+: CNil](a)) } val r1 = in1.flatMap(coIdentity) @@ -181,7 +182,7 @@ class CoproductTests { assertTypedEquals[I :+: S :+: CNil](is, r2) object coSquare extends Poly1 { - implicit def default[A] = at[A](a => Coproduct[A :+: A :+: CNil](a)) + implicit def default[A]: Case.Aux[A, A :+: A :+: CNil] = at[A](a => Coproduct[A :+: A :+: CNil](a)) } val r3 = in1.flatMap(coSquare) @@ -192,9 +193,9 @@ class CoproductTests { Coproduct[I :+: I :+: S :+: S :+: CNil](1), r4) object complex extends Poly1 { - implicit def caseInt = at[Int](i => Coproduct[S :+: CNil](i.toString)) - implicit def caseString = at[String](s => Coproduct[C :+: D :+: CNil](s(0))) - implicit def caseDouble = at[Double](d => Coproduct[I :+: S :+: CNil](d.toInt)) + implicit def caseInt: Case.Aux[Int, S :+: CNil] = at[Int](i => Coproduct[S :+: CNil](i.toString)) + implicit def caseString: Case.Aux[String, C :+: D :+: CNil] = at[String](s => Coproduct[C :+: D :+: CNil](s(0))) + implicit def caseDouble: Case.Aux[Double, I :+: S :+: CNil] = at[Double](d => Coproduct[I :+: S :+: CNil](d.toInt)) } val r5 = isd.flatMap(complex) @@ -270,7 +271,7 @@ class CoproductTests { import poly.identity object addSize extends Poly2 { - implicit def default[T](implicit st: size.Case.Aux[T, Int]) = + implicit def default[T](implicit st: size.Case.Aux[T, Int]): Case.Aux[Int, T, Int] = at[Int, T] { (acc, t) => acc + size(t) } } @@ -417,7 +418,7 @@ class CoproductTests { @Test def testWithKeys: Unit = { - type U = Union.`"i" -> Int, "s" -> String, "b" -> Boolean`.T + type U = ("i" ->> Int) :+: ("s" ->> String) :+: ("b" ->> Boolean) :+: CNil val cKeys = Keys[U].apply() val u1 = Coproduct[ISB](23).zipWithKeys(cKeys) @@ -446,7 +447,7 @@ class CoproductTests { // Explicit type argument { - val u1 = Coproduct[ISB](23).zipWithKeys[HList.`"i", "s", "b"`.T] + val u1 = Coproduct[ISB](23).zipWithKeys["i" :: "s" :: "b" :: HNil] val v1 = u1.get("i") typed[Option[Int]](v1) assertEquals(Some(23), v1) @@ -454,7 +455,7 @@ class CoproductTests { } { - val u2 = Coproduct[ISB]("foo").zipWithKeys[HList.`"i", "s", "b"`.T] + val u2 = Coproduct[ISB]("foo").zipWithKeys["i" :: "s" :: "b" :: HNil] val v2 = u2.get("s") typed[Option[String]](v2) assertEquals(Some("foo"), v2) @@ -462,7 +463,7 @@ class CoproductTests { } { - val u3 = Coproduct[ISB](true).zipWithKeys[HList.`"i", "s", "b"`.T] + val u3 = Coproduct[ISB](true).zipWithKeys["i" :: "s" :: "b" :: HNil] val v3 = u3.get("b") typed[Option[Boolean]](v3) assertEquals(Some(true), v3) @@ -1768,7 +1769,8 @@ class CoproductTests { def testToHList: Unit = { type CISB = Int :+: String :+: Boolean :+: CNil type PISBa = Int :: String :: Boolean :: HNil - type PISBb = the.`ToHList[CISB]`.Out + val toHlist = ToHList[CISB] + type PISBb = toHlist.Out implicitly[PISBa =:= PISBb] } @@ -1821,26 +1823,20 @@ class CoproductTests { import syntax.singleton._ { - type C = Coproduct.` `.T - - implicitly[C =:= CNil] - } - - { - type C = Coproduct.`Int`.T + type C = Int :+: CNil typed[C](Inl(23)) } { - type C = Coproduct.`Int, String`.T + type C = Int :+: String :+: CNil typed[C](Inl(23)) typed[C](Inr(Inl("foo"))) } { - type C = Coproduct.`Int, String, Boolean`.T + type C = Int :+: String :+: Boolean :+: CNil typed[C](Inl(23)) typed[C](Inr(Inl("foo"))) @@ -1850,13 +1846,13 @@ class CoproductTests { // Literal types { - type C = Coproduct.`2`.T + type C = 2 :+: CNil typed[C](Inl(2.narrow)) } { - type C = Coproduct.`2, "a", true`.T + type C = 2 :+: "a" :+: true :+: CNil typed[C](Inl(2.narrow)) typed[C](Inr(Inl("a".narrow))) @@ -1864,7 +1860,7 @@ class CoproductTests { } { - type C = Coproduct.`2`.T + type C = 2 :+: CNil illTyped(""" typed[C](Inl(3.narrow)) """) () @@ -1873,7 +1869,7 @@ class CoproductTests { // Mix of standard and literal types { - type C = Coproduct.`2, String, true`.T + type C = 2 :+: String :+: true :+: CNil typed[C](Inl(2.narrow)) typed[C](Inr(Inl("a"))) @@ -1888,11 +1884,9 @@ class CoproductTests { assertTypedEquals(HNil, Reify[CNil].apply()) - val s1 = Coproduct.`"a"` - assertTypedEquals("a".narrow :: HNil, Reify[s1.T].apply()) + assertTypedEquals("a".narrow :: HNil, Reify["a" :+: CNil].apply()) - val s2 = Coproduct.`"a", 1, "b", true` - assertEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify[s2.T].apply()) + assertEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify["a" :+: 1 :+: "b" :+: true :+: CNil].apply()) val gen = Generic[Enum] assertEquals(A :: B :: C :: HNil, Reify[gen.Repr].apply()) diff --git a/core/src/test/scala/shapeless/default.scala b/core/src/test/scala/shapeless/default.scala index f1de92fd5..d88cd4387 100644 --- a/core/src/test/scala/shapeless/default.scala +++ b/core/src/test/scala/shapeless/default.scala @@ -6,6 +6,7 @@ import org.junit.Test import org.junit.Assert._ import shapeless.test.illTyped import shapeless.testutil.assertTypedEquals +import labelled.->> // Intentionally defined as a top-level class - (compile time) reflection API not behaving // the same way compared to definitions in a singleton, like CC below. @@ -43,21 +44,13 @@ object DefaultTestDefinitions { object SemiAuto { case class CCl1(i: Int = 0) - object CCl1 { - implicit val default = Default[CCl1] - } + object CCl1 case class CCl2(i: Int) - trait CCl2Companion { - def default: Default[CCl2] - } - object CCl2 extends CCl2Companion { - implicit val default = Default[CCl2] - } + trait CCl2Companion + object CCl2 extends CCl2Companion - case object CObj { - implicit val default = Default[CObj.type] - } + case object CObj } class DefaultRun extends Exception("Default value was run") @@ -109,7 +102,7 @@ class DefaultTests { @Test def simpleAsRecord: Unit = { val default = Default.AsRecord[CC].apply() - assertTypedEquals[Record.`"s" -> String, "flagOpt" -> Option[Boolean]`.T]( + assertTypedEquals[("s" ->> String) :: ("flagOpt" ->> Option[Boolean]) :: HNil]( Record(s = "b", flagOpt = Some(true)), default ) @@ -118,7 +111,7 @@ class DefaultTests { @Test def simpleFromPathAsRecord: Unit = { val default = Default.AsRecord[definitions.CC].apply() - assertTypedEquals[Record.`"s" -> String, "flagOpt" -> Option[Boolean]`.T]( + assertTypedEquals[("s" ->> String) :: ("flagOpt" ->> Option[Boolean]) :: HNil]( Record(s = "b", flagOpt = Some(true)), default ) @@ -219,10 +212,6 @@ class DefaultTests { val default2 = Default[CCl2] val default3 = Default[CObj.type] - assertSame(CCl1.default, default1) - assertSame(CCl2.default, default2) - assertSame(CObj.default, default3) - assertTypedEquals[Some[Int] :: HNil](Some(0) :: HNil, default1()) assertTypedEquals[None.type :: HNil](None :: HNil, default2()) assertTypedEquals[HNil](HNil, default3()) diff --git a/core/src/test/scala/shapeless/generic.scala b/core/src/test/scala/shapeless/generic.scala index a497e7c56..7d29b2396 100644 --- a/core/src/test/scala/shapeless/generic.scala +++ b/core/src/test/scala/shapeless/generic.scala @@ -31,10 +31,10 @@ package GenericTestsAux { case class Orange() extends Fruit object showFruit extends Poly1 { - implicit def caseApple = at[Apple](_ => "Pomme") - implicit def casePear = at[Pear](_ => "Poire") - implicit def caseBanana = at[Banana](_ => "Banane") - implicit def caseOrange = at[Orange](_ => "Orange") + implicit def caseApple: Case.Aux[Apple, String] = at[Apple](_ => "Pomme") + implicit def casePear: Case.Aux[Pear, String] = at[Pear](_ => "Poire") + implicit def caseBanana: Case.Aux[Banana, String] = at[Banana](_ => "Banane") + implicit def caseOrange: Case.Aux[Orange, String] = at[Orange](_ => "Orange") } sealed trait AbstractSingle @@ -50,9 +50,9 @@ package GenericTestsAux { case object C extends Enum object pickFruit extends Poly1 { - implicit def caseA = at[A.type](_ => Apple()) - implicit def caseB = at[B.type](_ => Banana()) - implicit def caseC = at[C.type](_ => Pear()) + implicit def caseA: Case.Aux[A.type, Apple] = at[A.type](_ => Apple()) + implicit def caseB: Case.Aux[B.type, Banana] = at[B.type](_ => Banana()) + implicit def caseC: Case.Aux[C.type, Pear] = at[C.type](_ => Pear()) } sealed trait L @@ -70,27 +70,27 @@ package GenericTestsAux { case class PersonWithPseudonims(name: String, nicks: String*) trait starLP extends Poly1 { - implicit def default[T] = at[T](identity) + implicit def default[T]: Case.Aux[T, T] = at[T](identity) } object star extends starLP { - implicit def caseString = at[String](_+"*") + implicit def caseString: Case.Aux[String, String] = at[String](_+"*") - implicit def caseIso[T, L <: HList](implicit gen: Generic.Aux[T, L], mapper: => hl.Mapper.Aux[this.type, L, L]) = + implicit def caseIso[T, L <: HList](implicit gen: Generic.Aux[T, L], mapper: => hl.Mapper.Aux[this.type, L, L]): Case.Aux[T, T] = at[T](t => gen.from(mapper(gen.to(t)))) } trait incLP extends Poly1 { - implicit def default[T] = at[T](identity) + implicit def default[T]: Case.Aux[T, T] = at[T](identity) } object inc extends incLP { - implicit val caseInt = at[Int](_+1) + implicit val caseInt: Case.Aux[Int, Int] = at[Int](_+1) - implicit def caseProduct[T, L <: HList](implicit gen: Generic.Aux[T, L], mapper: hl.Mapper.Aux[this.type, L, L]) = + implicit def caseProduct[T, L <: HList](implicit gen: Generic.Aux[T, L], mapper: hl.Mapper.Aux[this.type, L, L]): Case.Aux[T, T] = at[T](t => gen.from(gen.to(t).map(inc))) - implicit def caseCoproduct[T, L <: Coproduct](implicit gen: Generic.Aux[T, L], mapper: cp.Mapper.Aux[this.type, L, L]) = + implicit def caseCoproduct[T, L <: Coproduct](implicit gen: Generic.Aux[T, L], mapper: cp.Mapper.Aux[this.type, L, L]): Case.Aux[T, T] = at[T](t => gen.from(gen.to(t).map(inc))) } @@ -128,13 +128,8 @@ package GenericTestsAux { case class OAB(i: Int) extends OA with OB object SemiAuto { - case object CObj { - implicit val gen = Generic[CObj.type] - } - - object NonCObj { - implicit val gen = Generic[NonCObj.type] - } + case object CObj + object NonCObj } case class CCOrdered[A: Ordering](value: A) @@ -599,8 +594,8 @@ class GenericTests { illTyped(" IsTuple[Single] ") illTyped(" IsTuple[Person] ") illTyped(" IsTuple[Fruit] ") - illTyped(""" IsTuple[Record.`"i" -> Int, "s" -> String`.T] """) - illTyped(""" IsTuple[Union.`"i" -> Int, "s" -> String`.T] """) + illTyped(""" IsTuple[("i" ->> Int) :: ("s" ->> String) :: HNil] """) + illTyped(""" IsTuple[("i" ->> Int) :+: ("s" ->> String) :: CNil] """) illTyped(" IsTuple[Int] ") illTyped(" IsTuple[String] ") illTyped(" IsTuple[Array[Int]] ") @@ -624,8 +619,8 @@ class GenericTests { illTyped(" HasProductGeneric[CNil] ") illTyped(" HasProductGeneric[Int :+: String :+: CNil] ") illTyped(" HasProductGeneric[Fruit] ") - illTyped(""" HasProductGeneric[Record.`"i" -> Int, "s" -> String`.T] """) - illTyped(""" HasProductGeneric[Union.`"i" -> Int, "s" -> String`.T] """) + illTyped(""" HasProductGeneric[("i" ->> Int) :: ("s" ->> String) :: HNil] """) + illTyped(""" HasProductGeneric[("i" ->> Int) :+: ("s" ->> String) :: CNil] """) illTyped(" HasProductGeneric[Int] ") illTyped(" HasProductGeneric[String] ") illTyped(" HasProductGeneric[Array[Int]] ") @@ -647,8 +642,8 @@ class GenericTests { illTyped(" HasCoproductGeneric[A.type] ") illTyped(" HasCoproductGeneric[Single] ") illTyped(" HasCoproductGeneric[Person] ") - illTyped(""" HasCoproductGeneric[Record.`"i" -> Int, "s" -> String`.T] """) - illTyped(""" HasCoproductGeneric[Union.`"i" -> Int, "s" -> String`.T] """) + illTyped(""" HasCoproductGeneric[("i" ->> Int) :: ("s" ->> String) :: HNil] """) + illTyped(""" HasCoproductGeneric[("i" ->> Int) :+: ("s" ->> String) :: CNil] """) illTyped(" HasCoproductGeneric[Int] ") illTyped(" HasCoproductGeneric[String] ") illTyped(" HasCoproductGeneric[Array[Int]] ") @@ -666,8 +661,8 @@ class GenericTests { illTyped(" Generic[Int :: String :: HNil] ") illTyped(" Generic[CNil] ") illTyped(" Generic[Int :+: String :+: CNil] ") - illTyped(""" Generic[Record.`"i" -> Int, "s" -> String`.T] """) - illTyped(""" Generic[Union.`"i" -> Int, "s" -> String`.T] """) + illTyped(""" Generic[("i" ->> Int) :: ("s" ->> String) :: HNil] """) + illTyped(""" Generic[("i" ->> Int) :+: ("s" ->> String) :: CNil] """) } sealed trait Color @@ -713,9 +708,6 @@ class GenericTests { val gen1 = Generic[CObj.type] val gen2 = Generic[NonCObj.type] - assertSame(gen1, CObj.gen) - assertSame(gen2, NonCObj.gen) - assertTypedEquals[HNil](HNil, gen1.to(CObj)) assertTypedEquals[CObj.type](CObj, gen1.from(HNil)) assertTypedEquals[HNil](HNil, gen2.to(NonCObj)) diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 34318a315..611fe46f5 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -222,7 +222,7 @@ class HListTests { } object dup extends Poly1 { - implicit def default[T] = at[T](t => t :: t :: HNil) + implicit def default[T]: Case.Aux[T, T :: T :: HNil] = at[T](t => t :: t :: HNil) } @Test @@ -1404,32 +1404,6 @@ class HListTests { assertEquals(2.0, sd, Double.MinPositiveValue) } @Test - def testSelectMany: Unit = { - val si = 1 :: true :: "foo" :: 2.0 :: HNil - - val si1 = si.selectManyType[HNil] - assertTypedEquals[HNil](HNil, si1) - - val si2 = si.selectManyType[_0::HNil] - assertTypedEquals[Int::HNil](1::HNil, si2) - - val si3 = si.selectManyType[_2::HNil] - assertTypedEquals[String::HNil]("foo"::HNil, si3) - - val si4 = si.selectManyType[_0::_1::_2::_3::HNil] - assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, si4) - - val si5 = si.selectMany(0) - assertTypedEquals[Int::HNil](1::HNil, si5) - - val si6 = si.selectMany(2) - assertTypedEquals[String::HNil]("foo"::HNil, si6) - - val si7 = si.selectMany(0,1,2,3) - assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, si7) - - } - @Test def testSelectRange: Unit = { val sl = 1 :: true :: "foo" :: 2.0 :: HNil @@ -2137,8 +2111,8 @@ class HListTests { } object combine extends Poly { - implicit def caseCharString = use((c : Char, s : String) => s.indexOf(c)) - implicit def caseIntBoolean = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") + implicit def caseCharString: ProductCase.Aux[Char :: String :: HNil, Int] = use((c : Char, s : String) => s.indexOf(c)) + implicit def caseIntBoolean: ProductCase.Aux[Int :: Boolean :: HNil, String] = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") } object toMapL extends Poly2 { @@ -2283,7 +2257,7 @@ class HListTests { object empty extends Poly2 object add extends Poly2 { - implicit val caseIntInt = at[Int, Int](_ + _) + implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) } // HNil zipWith HNil (emptyFn) @@ -2310,9 +2284,9 @@ class HListTests { val right: Right = 2 :: 2.3 :: "3.4" :: true :: HNil object zipFn extends Poly2 { - implicit val caseIntInt = at[Int, Int](_ + _) - implicit val caseStringDouble = at[String, Double](_ + " -> " + _.toString) - implicit val caseDoubleString = at[Double, String](_ + _.toDouble) + implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) + implicit val caseStringDouble: Case.Aux[String, Double, String] = at[String, Double](_ + " -> " + _.toString) + implicit val caseDoubleString: Case.Aux[Double, String, Double] = at[Double, String](_ + _.toDouble) } val r5 = left.zipWith(right)(zipFn) @@ -2341,7 +2315,7 @@ class HListTests { """) object noIntFn extends Poly2 { - implicit val caseDoubleDouble = at[Double, Double](_ + _) + implicit val caseDoubleDouble: Case.Aux[Double, Double, Double] = at[Double, Double](_ + _) } illTyped(""" @@ -2379,7 +2353,7 @@ class HListTests { // Explicit type argument { - val result = orig.values.zipWithKeys[HList.`"intField", "boolField"`.T] + val result = orig.values.zipWithKeys["intField" :: "boolField" :: HNil] sameTyped(orig)(result) assertEquals(orig, result) val int = result.get("intField") @@ -2389,8 +2363,8 @@ class HListTests { illTyped("""result.get("otherField")""") // key/value lengths must match up - illTyped(""" orig.tail.values.zipWithKeys[HList.`"intField", "boolField"`.T] """) - illTyped(""" orig.values.zipWithKeys[HList.`"boolField"`.T] """) + illTyped(""" orig.tail.values.zipWithKeys["intField" :: "boolField" :: HNil] """) + illTyped(""" orig.values.zipWithKeys["boolField" :: HNil] """) } } @@ -2401,8 +2375,8 @@ class HListTests { object empty extends Poly1 object complex extends Poly1 { - implicit val caseInt = at[Int](_.toDouble) - implicit val caseString = at[String](_ => 1) + implicit val caseInt: Case.Aux[Int, Double] = at[Int](_.toDouble) + implicit val caseString: Case.Aux[String, Int] = at[String](_ => 1) } val in: Int :: String :: Double :: HNil = 1 :: "foo" :: 2.2 :: HNil @@ -2791,9 +2765,9 @@ class HListTests { } object smear extends Poly { - implicit val caseIntInt = use((x: Int, y: Int) => x + y) - implicit val caseStringInt = use((x: String, y: Int) => x.toInt + y) - implicit val caseIntString = use((x: Int, y: String) => x + y.toInt) + implicit val caseIntInt: ProductCase.Aux[Int :: Int :: HNil, Int] = use((x: Int, y: Int) => x + y) + implicit val caseStringInt: ProductCase.Aux[String :: Int :: HNil, Int] = use((x: String, y: Int) => x.toInt + y) + implicit val caseIntString: ProductCase.Aux[Int :: String :: HNil, Int] = use((x: Int, y: String) => x + y.toInt) } @Test @@ -2958,10 +2932,10 @@ class HListTests { @Test def testPolyFill = { object zero extends Poly0 { - implicit val zeroInt = at[Int](0) + implicit val zeroInt: Case0[Int] = at[Int](0) } - implicit val emptyString = zero.at[String]("") + implicit val emptyString: zero.Case0[String] = zero.at[String]("") val out = HList.fillWith[Int :: String :: Int :: HNil](zero) assertEquals(out, 0 :: "" :: 0 :: HNil) @@ -3023,7 +2997,8 @@ class HListTests { def testToCoproduct: Unit = { type PISB = Int :: String :: Boolean :: HNil type CISBa = Int :+: String :+: Boolean :+: CNil - type CISBb = the.`ToCoproduct[PISB]`.Out + val toCoproduct = ToCoproduct[PISB] + type CISBb = toCoproduct.Out implicitly[CISBa =:= CISBb] } @@ -3031,11 +3006,13 @@ class HListTests { def testToSum: Unit = { type PISB = Int :: String :: Boolean :: HNil type CISBa = Int :+: String :+: Boolean :+: CNil - type SISBa = the.`ToSum[PISB]`.Out + val toSum1 = ToSum[PISB] + type SISBa = toSum1.Out implicitly[CISBa =:= SISBa] type PIISSB = Int :: Int :: String :: String :: Boolean :: HNil - type SISBb = the.`ToSum[PIISSB]`.Out + val toSum2 = ToSum[PIISSB] + type SISBb = toSum2.Out implicitly[CISBa =:= SISBb] } @@ -3043,157 +3020,25 @@ class HListTests { def testHListTypeSelector: Unit = { import syntax.singleton._ - typed[HList.` `.T](HNil) + typed[HNil](HNil) - typed[HList.`Int`.T](23 :: HNil) + typed[Int :: HNil](23 :: HNil) - typed[HList.`Int, String`.T](23 :: "foo" :: HNil) + typed[Int :: String :: HNil](23 :: "foo" :: HNil) - typed[HList.`Int, String, Boolean`.T](23 :: "foo" :: true :: HNil) + typed[Int :: String :: Boolean :: HNil](23 :: "foo" :: true :: HNil) // Literal types - typed[HList.`2`.T](2.narrow :: HNil) + typed[2 :: HNil](2.narrow :: HNil) - typed[HList.`2, "a", true`.T](2.narrow :: "a".narrow :: true.narrow :: HNil) + typed[2 :: "a" :: true :: HNil](2.narrow :: "a".narrow :: true.narrow :: HNil) - illTyped(""" typed[HList.`2`.T](3.narrow :: HNil) """) + illTyped(""" typed[2 :: HNil](3.narrow :: HNil) """) // Mix of standard and literal types - typed[HList.`2, String, true`.T](2.narrow :: "a" :: true.narrow :: HNil) - } - - object Foo extends ProductArgs { - def applyProduct[L <: HList](args: L): L = args - } - - @Test - def testProductArgs: Unit = { - val l = Foo(23, "foo", true) - typed[Int :: String :: Boolean :: HNil](l) - - val v1 = l.head - typed[Int](v1) - assertEquals(23, v1) - - val v2 = l.tail.head - typed[String](v2) - assertEquals("foo", v2) - - val v3 = l.tail.tail.head - typed[Boolean](v3) - assertEquals(true, v3) - - val v4 = l.tail.tail.tail - typed[HNil](v4) - - illTyped(""" - r.tail.tail.tail.head - """) - } - - object SFoo extends SingletonProductArgs { - def applyProduct[L <: HList](args: L): L = args - } - - case class Quux(i: Int, s: String, b: Boolean) - - object selectAll extends SingletonProductArgs { - class Apply[K <: HList] { - def from[T, R <: HList, S <: HList, Out](t: T) - (implicit - gen: LabelledGeneric.Aux[T, R], - sel: SelectAll.Aux[R, K, S], - tp: Tupler.Aux[S, Out] - ): Out = - tp(sel(gen.to(t))) - } - - def applyProduct[K <: HList](keys: K) = new Apply[K] - } - - trait NonSingletonHNilTC[T] - object NonSingletonHNilTC { - def apply[T](t: T)(implicit i: NonSingletonHNilTC[T]): NonSingletonHNilTC[T] = i - - implicit val nsHNilTC: NonSingletonHNilTC[HNil] = new NonSingletonHNilTC[HNil] {} - } - - @Test - def testSingletonProductArgs: Unit = { - object Obj - - val l = SFoo(23, "foo", "bar", Obj, true) - typed[23 :: "foo" :: "bar" :: Obj.type :: true :: HNil](l) - - // Annotations on the LHS here and subsequently, otherwise scalac will - // widen the RHS to a non-singleton type. - val v1: 23 = l.head - assertEquals(23, v1) - - val v2: "foo" = l.tail.head - assertEquals("foo", v2) - - val v3: "bar" = l.tail.tail.head - assertEquals("bar", v3) - - val v4: Obj.type = l.tail.tail.tail.head - assertEquals(Obj, v4) - - val v5: true = l.tail.tail.tail.tail.head - assertEquals(true, v5) - - val v6 = l.tail.tail.tail.tail.tail - typed[HNil](v6) - - illTyped("r.tail.tail.tail.tail.tail.tail.head") - - // Verify that we infer HNil rather than HNil.type at the end - NonSingletonHNilTC(SFoo(23).tail) - NonSingletonHNilTC(SFoo()) - - val quux = Quux(23, "foo", true) - val ib = selectAll("i", "b").from(quux) - typed[(Int, Boolean)](ib) - assertEquals((23, true), ib) - } - - object Bar extends FromProductArgs { - def sumLabel(k: String, i1: Int, i2: Int) = (k, i1 + i2) - def sumImplicitLabel(k: String, i1: Int)(implicit i2: Int) = (k, i1 + i2) - def sumMultipleParamListLabel(k: String, i1: Int)(i2: Int) = (k, i1 + i2) - } - - @Test - def testFromProductArgs: Unit = { - val p = "foo" :: 1 :: 3 :: HNil - - val v1 = Bar.sumLabelProduct(p) - typed[(String, Int)](v1) - assertEquals(("foo", 4), v1) - - val p2 = "bar" :: 1 :: 2 :: HNil - val v2 = Bar.sumMultipleParamListLabelProduct(p2) - typed[(String, Int)](v2) - assertEquals(("bar", 3), v2) - - illTyped(""" - Bar.sumImplicitLabelProduct("foo" :: 1 :: 3 :: HNil) - """) - - implicit val i2 = 7 - val v3 = Bar.sumImplicitLabelProduct("foo" :: 1 :: HNil) - typed[(String, Int)](v3) - assertEquals(("foo", 8), v3) - - illTyped(""" - Bar.sumLabelProduct("foo" :: "bar" :: 1 :: 2 :: HNil) - """) - - illTyped(""" - Bar.sumMultipleParamListLabelProduct("foo" :: "1" :: 2 :: 3 :: HNil) - """) + typed[2 :: String :: true :: HNil](2.narrow :: "a" :: true.narrow :: HNil) } @Test @@ -3221,78 +3066,10 @@ class HListTests { } - object FooNat extends NatProductArgs { - def applyNatProduct[L <: HList](args: L): L = args - } - object FooNatTypeParams extends NatProductArgs { - def applyNatProduct[L <: HList](implicit len: Length[L]) = len() - } - - @Test - def testNatProductArgs: Unit = { - val l = FooNat(1, 2, 3) - typed[_1 :: _2 :: _3 :: HNil](l) - - val v1 = l.head - typed[_1](v1) - assertEquals(_1, v1) - - val v2 = l.tail.head - typed[_2](v2) - assertEquals(_2, v2) - - val v3 = l.tail.tail.head - typed[_3](v3) - assertEquals(_3, v3) - - val v4 = l.tail.tail.tail - typed[HNil](v4) - - illTyped(""" - r.tail.tail.tail.head - """) - val res = FooNatTypeParams(1,2,3,4) - assertEquals(_4,res) - } - - implicit class Interpolator(val sc: StringContext) { - class Args extends ProductArgs { - def applyProduct[L <: HList](l: L): L = l - } - - val hlist: Args = new Args - } - - @Test - def testStringInterpolator: Unit = { - val (i, s, b) = (23, "foo", true) - val l = hlist"Int: $i, String: $s, Boolean: $b" - typed[Int :: String :: Boolean :: HNil](l) - - val v1 = l.head - typed[Int](v1) - assertEquals(23, v1) - - val v2 = l.tail.head - typed[String](v2) - assertEquals("foo", v2) - - val v3 = l.tail.tail.head - typed[Boolean](v3) - assertEquals(true, v3) - - val v4 = l.tail.tail.tail - typed[HNil](v4) - - illTyped(""" - r.tail.tail.tail.head - """) - } - @Test def testCollectFirst: Unit = { object Foo extends Poly1{ - implicit def iinst = at[Int]{ _ + 1 } + implicit def iinst: Case.Aux[Int, Int] = at[Int]{ _ + 1 } } val hlist1 = "foo" :: 2.0 :: 1 :: HNil assertTypedEquals[Int](hlist1.collectFirst(Foo), 2) @@ -3304,7 +3081,7 @@ class HListTests { @Test def testGrouper: Unit = { object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]) = at[N](_ => toi()) + implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) } def range[R <: HList](a: Nat, b: Nat)(implicit range: ops.nat.Range.Aux[a.N, b.N, R], @@ -3426,14 +3203,12 @@ class HListTests { assertTypedEquals(HNil, Reify[HNil].apply()) - val s1 = HList.`"a"` - assertTypedEquals("a".narrow :: HNil, Reify[s1.T].apply()) + assertTypedEquals("a".narrow :: HNil, Reify["a" :: HNil].apply()) - val s2 = HList.`"a", 1, "b", true` - assertTypedEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify[s2.T].apply()) + assertTypedEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify["a" :: 1 :: "b" :: true :: HNil].apply()) illTyped("Reify[String :: Int :: HNil]") - illTyped("""Reify[String :: HList.`"a", 1, "b", true`.T]""") + illTyped("""Reify[String :: ("a" :: 1 :: "b" :: true :: HNil)]""") } @Test diff --git a/core/src/test/scala/shapeless/hmap.scala b/core/src/test/scala/shapeless/hmap.scala index 86d7fa178..de4dfb621 100644 --- a/core/src/test/scala/shapeless/hmap.scala +++ b/core/src/test/scala/shapeless/hmap.scala @@ -24,8 +24,8 @@ import shapeless.test._ class HMapTests { class BiMapIS[K, V] - implicit val intToString = new BiMapIS[Int, String] - implicit val stringToInt = new BiMapIS[String, Int] + implicit val intToString: BiMapIS[Int, String] = new BiMapIS[Int, String] + implicit val stringToInt: BiMapIS[String, Int] = new BiMapIS[String, Int] @Test def testBasics: Unit = { @@ -166,7 +166,7 @@ class HMapTests { trait M[A] class Mapping[K, V] - implicit def mappingFromM[A, B <: M[A]] = new Mapping[A,B] + implicit def mappingFromM[A, B <: M[A]]: Mapping[A, B] = new Mapping[A,B] case class X(x: Int) extends M[X.type] object X diff --git a/core/src/test/scala/shapeless/implicits.scala b/core/src/test/scala/shapeless/implicits.scala index 7bc211b97..9725a3cf5 100644 --- a/core/src/test/scala/shapeless/implicits.scala +++ b/core/src/test/scala/shapeless/implicits.scala @@ -25,7 +25,7 @@ import test.illTyped object CachedTestDefns { trait CachedTC[T] object CachedTC { - implicit def mkTC[T] = new CachedTC[T] {} + implicit def mkTC[T]: CachedTC[T] = new CachedTC[T] {} implicit val cached: CachedTC[String] = cachedImplicit } @@ -193,8 +193,8 @@ class CachedTest { @Test def testAmbiguous: Unit = { - implicit val a = new Foo[String] { } - implicit val b = new Foo[String] { } + implicit val a: Foo[String] = new Foo[String] { } + implicit val b: Foo[String] = new Foo[String] { } illTyped( "cachedImplicit[Foo[String]]" ) diff --git a/core/src/test/scala/shapeless/labelledgeneric.scala b/core/src/test/scala/shapeless/labelledgeneric.scala index 50f87ae73..ada782068 100644 --- a/core/src/test/scala/shapeless/labelledgeneric.scala +++ b/core/src/test/scala/shapeless/labelledgeneric.scala @@ -25,6 +25,7 @@ import syntax.singleton._ import test._ import testutil._ import union._ +import labelled.->> object LabelledGenericTestsAux { case class Book(author: String, title: String, id: Int, price: Double) @@ -57,11 +58,11 @@ object LabelledGenericTestsAux { ("authors" ->> Seq("Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides")) :: HNil - type BookRec = Record.`"author" -> String, "title" -> String, "id" -> Int, "price" -> Double`.T + type BookRec = ("author" ->> String) :: ("title" ->> String) :: ("id" ->> Int) :: ("price" ->> Double) :: HNil type BookKeys = Keys[BookRec] type BookValues = Values[BookRec] - type BookWithMultipleAuthorsRec = Record.`"title" -> String, "id" -> Int, "authors" -> Seq[String]`.T + type BookWithMultipleAuthorsRec = ("title" ->> String) :: ("id" ->> Int) :: ("authors" ->> Seq[String]) :: HNil sealed trait Tree @@ -320,7 +321,7 @@ class LabelledGenericTests { @Test def testCoproductBasics: Unit = { - type TreeUnion = Union.`"Leaf" -> Leaf, "Node" -> Node`.T + type TreeUnion = ("Leaf" ->> Leaf) :+: ("Node" ->> Node) :+: CNil val gen = LabelledGeneric[Tree] @@ -335,9 +336,9 @@ class LabelledGenericTests { val nccb = new NonCCB(true, 2.0) val ancc: AbstractNonCC = ncca - type NonCCARec = Record.`"i" -> Int, "s" -> String`.T - type NonCCBRec = Record.`"b" -> Boolean, "d" -> Double`.T - type AbsUnion = Union.`"NonCCA" -> NonCCA, "NonCCB" -> NonCCB`.T + type NonCCARec = ("i" ->> Int) :: ("s" ->> String) :: HNil + type NonCCBRec = ("b" ->> Boolean) :: ("d" ->> Double) :: HNil + type AbsUnion = ("NonCCA" ->> NonCCA) :+: ("NonCCB" ->> NonCCB) :+: CNil val genA = LabelledGeneric[NonCCA] val genB = LabelledGeneric[NonCCB] @@ -376,7 +377,7 @@ class LabelledGenericTests { val nccc = NonCCWithCompanion(23, "foo") val rec = ("i" ->> 23) :: ("s" ->> "foo") :: HNil - type NonCCRec = Record.`"i" -> Int, "s" -> String`.T + type NonCCRec = ("i" ->> Int) :: ("s" ->> String) :: HNil val gen = LabelledGeneric[NonCCWithCompanion] @@ -395,7 +396,7 @@ class LabelledGenericTests { (new NonCCLazy(c, b), new NonCCLazy(a, c), new NonCCLazy(b, a)) val rec = "prev" ->> a :: "next" ->> c :: HNil - type LazyRec = Record.`"prev" -> NonCCLazy, "next" -> NonCCLazy`.T + type LazyRec = ("prev" ->> NonCCLazy) :: ("next" ->> NonCCLazy) :: HNil val gen = LabelledGeneric[NonCCLazy] @@ -432,12 +433,12 @@ class LabelledGenericTests { implicitly[TC[DummyTagged]] - type R = Record.`"i" -> Int @@ CustomTag`.T + type R = ("i" ->> (Int @@ CustomTag)) :: HNil val lgen = LabelledGeneric[Dummy] implicitly[lgen.Repr =:= R] implicitly[TC[R]] - type RT = Record.`"b" -> Boolean, "i" -> Int @@ CustomTag`.T + type RT = ("b" ->> Boolean) :: ("i" ->> (Int @@ CustomTag)) :: HNil val lgent = LabelledGeneric[DummyTagged] implicitly[lgent.Repr =:= RT] implicitly[TC[RT]] diff --git a/core/src/test/scala/shapeless/lazy.scala b/core/src/test/scala/shapeless/lazy.scala deleted file mode 100644 index bbeea3b74..000000000 --- a/core/src/test/scala/shapeless/lazy.scala +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (c) 2013-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import org.junit.Test -import org.junit.Assert._ - -import scala.collection.mutable.ListBuffer - -import test._ - -class LazyStrictTests { - - @Test - def testEffectOrder: Unit = { - val effects = ListBuffer[Int]() - - implicit def int: Int = { effects += 3; 23 } - implicit def long: Long = { effects += 6; 23 } - - def summonLazyInt(implicit li: => Int): Int = { - effects += 2 - val i = li - effects += 4 - i - } - - def summonStrictLong(implicit sl: Long): Long = { - effects += 7 - val i = sl - effects += 8 - i - } - - effects += 1 - val li = summonLazyInt - effects += 5 - val sl = summonStrictLong - effects += 9 - - assertEquals(23, li) - assertEquals(23, sl) - assertEquals(1 to 9, effects.toList) - } - - @Test - def testDefConversion: Unit = { - val effects = ListBuffer[Int]() - - def effectfulLazyInt: Int = { effects += 3 ; 23 } - - def useEffectfulLazyInt(li: => Int): Int = { - effects += 2 - val i = li - effects += 4 - i - } - - def effectfulStrictInt: Int = { effects += 6 ; 23 } - - def useEffectfulStrictInt(li: Int): Int = { - effects += 7 - val i = li - effects += 8 - i - } - - effects += 1 - val il = useEffectfulLazyInt(effectfulLazyInt) - effects += 5 - val is = useEffectfulStrictInt(effectfulStrictInt) - effects += 9 - - assertEquals(23, il) - assertEquals(23, is) - assertEquals(1 to 9, effects.toList) - } - - @Test - def testLazyConversion: Unit = { - val effects = ListBuffer[Int]() - - lazy val effectfulLazyInt: Int = { effects += 3 ; 23 } - lazy val effectfulStrictInt: Int = { effects += 6 ; 23 } - - def useEffectfulLazyInt(li: => Int): Int = { - effects += 2 - val i = li - effects += 4 - i - } - - def useEffectfulStrictInt(li: Int): Int = { - effects += 7 - val i = li - effects += 8 - i - } - - effects += 1 - val il = useEffectfulLazyInt(effectfulLazyInt) - effects += 5 - val is = useEffectfulStrictInt(effectfulStrictInt) - effects += 9 - - assertEquals(23, il) - assertEquals(23, is) - assertEquals(1 to 9, effects.toList) - } - - @Test - def testInlineConversion: Unit = { - val effects = ListBuffer[Int]() - - def useEffectfulLazyInt(li: => Int): Int = { - effects += 3 - val i = li - effects += 4 - i - } - - def useEffectfulStrictInt(si: Int): Int = { - effects += 7 - val i = si - effects += 8 - i - } - - effects += 1 - val il = useEffectfulLazyInt({ effects += 2 ; 23 }) - effects += 5 - val is = useEffectfulStrictInt({ effects += 6 ; 23 }) - effects += 9 - - assertEquals(23, il) - assertEquals(23, is) - assertEquals(1 to 9, effects.toList) - } - - sealed trait List[+T] - case class Cons[T](hd: T, tl: List[T]) extends List[T] - sealed trait Nil extends List[Nothing] - case object Nil extends Nil - - trait Show[T] { - def apply(t: T): String - } - - def show[T](t: T)(implicit s: Show[T]) = s(t) - - trait CommonShows { - implicit def showInt: Show[Int] = _.toString - implicit def showNil: Show[Nil] = _ => "Nil" - } - - object LazyShows extends CommonShows { - implicit def showCons[T](implicit st: => Show[T], sl: => Show[List[T]]): Show[Cons[T]] = - t => s"Cons(${show(t.hd)(st)}, ${show(t.tl)(sl)})" - - implicit def showList[T](implicit sc: => Show[Cons[T]]): Show[List[T]] = { - case n: Nil => show(n) - case c: Cons[T] => show(c)(sc) - } - } - - object LazyStrictMixShows extends CommonShows { - implicit def showCons[T](implicit st: => Show[T], sl: => Show[List[T]]): Show[Cons[T]] = - t => s"Cons(${show(t.hd)(st)}, ${show(t.tl)(sl)})" - - implicit def showList[T](implicit sc: => Show[Cons[T]]): Show[List[T]] = { - case n: Nil => show(n) - case c: Cons[T] => show(c)(sc) - } - } - - @Test - def testRecursive: Unit = { - val l: List[Int] = Cons(1, Cons(2, Cons(3, Nil))) - - val lazyRepr = { - import LazyShows._ - show(l) - } - - val strictRepr = { - import LazyStrictMixShows._ - show(l) - } - - val expectedRepr = "Cons(1, Cons(2, Cons(3, Nil)))" - - assertEquals(expectedRepr, lazyRepr) - assertEquals(expectedRepr, strictRepr) - } - - trait Foo[T] - object Foo { - implicit def mkFoo[T]: Foo[T] = new Foo[T] {} - } - - @Test - def testMultiple: Unit = { - val foos = Lazy.values[Foo[Int] :: Foo[String] :: Foo[Boolean] :: HNil] - implicit val x :: y :: z :: HNil = foos - - typed[Foo[Int]](x) - typed[Foo[String]](y) - typed[Foo[Boolean]](z) - - val x1 = implicitly[Foo[Int]] - val y1 = implicitly[Foo[String]] - val z1 = implicitly[Foo[Boolean]] - - assertTrue(x1 eq x) - assertTrue(y1 eq y) - assertTrue(z1 eq z) - } - - trait Bar[A] { def foo(a: A): Unit } - object Bar { - implicit val intBar = new Bar[Int] { def foo(x: Int) = () } - } - - @Test - def testEta: Unit = { - //implicitly[=> Bar[Int]].value.foo _ - implicitly[Bar[Int]].foo _ - () - } - - trait Baz[T] { - type U - } - - object Baz { - def lazyBaz[T, U](t: T)(implicit bt: => Aux[T, U]): Aux[T, U] = bt - def strictBaz[T, U](t: T)(implicit bt: Aux[T, U]): Aux[T, U] = bt - - type Aux[T, U0] = Baz[T] { type U = U0 } - - implicit val bazIS: Aux[Int, String] = new Baz[Int] { type U = String } - implicit val bazBD: Aux[Boolean, Double] = new Baz[Boolean] { type U = Double } - } - - @Test - def testAux: Unit = { - val lIS = Baz.lazyBaz(23) - val sIS = Baz.strictBaz(23) - typed[Baz.Aux[Int, String]](lIS) - typed[Baz.Aux[Int, String]](sIS) - - val lBD = Baz.lazyBaz(true) - val sBD = Baz.strictBaz(true) - typed[Baz.Aux[Boolean, Double]](lBD) - typed[Baz.Aux[Boolean, Double]](sBD) - } - - @Test - def testExtractors: Unit = { - //implicitly[=> Generic[Symbol]] - implicitly[Generic[Symbol]] - - val x = { - case class Leaf[A](value: A) - //implicitly[=> Generic[Leaf[Int]]] - implicitly[Generic[Leaf[Int]]] - () - } - } - - @Test - def testNotFound: Unit = { - @scala.annotation.implicitNotFound("No U[${X}]") - trait U[X] - - trait V - - @scala.annotation.implicitNotFound("No W[${X}, ${Y}]") - trait W[X, Y] - - illTyped( - "lazily[U[String]]", - "(No U\\[String])|(could not find implicit value for parameter lv: => U\\[String])" - ) - - illTyped( - "lazily[V]", - "(could not find Lazy implicit value of type V)|(could not find implicit value for parameter lv: => V)" - ) - - illTyped( - "lazily[W[String, Int]]", - "(No W\\[String, Int])|(could not find implicit value for parameter lv: => W\\[String,Int])" - ) - } - - @Test - def testInteractionWithTaggedTypes: Unit = { - import tag._ - - class Readable[A] - trait IdTag - type Id = String @@ IdTag - - implicit def taggedStringReadable[T, M[_, _]]( - implicit ev: String @@ T =:= M[String, T] - ): Readable[M[String, T]] = new Readable - - implicitly[Readable[Id]] - //implicitly[=> Readable[Id]] - implicitly[Readable[Id]] - } -} diff --git a/core/src/test/scala/shapeless/lenses.scala b/core/src/test/scala/shapeless/lenses.scala index 760e4dc6f..20f6f1bf9 100644 --- a/core/src/test/scala/shapeless/lenses.scala +++ b/core/src/test/scala/shapeless/lenses.scala @@ -214,11 +214,11 @@ trait LensTests { val l = ("foo" ->> 42) :: ("bar" ->> "hi") :: HNil typed[LT](l) - val li = recordLens[LT]("foo") + val li = recordLens[LT, "foo"]("foo") assertEquals(42, li.get(l)) assertEquals(("foo" ->> 84) :: ("bar" ->> "hi") :: HNil, li.set(l)(84)) - val ls = recordLens[LT]("bar") + val ls = recordLens[LT, "bar"]("bar") assertEquals("hi", ls.get(l)) assertEquals(("foo" ->> 42) :: ("bar" ->> "bye") :: HNil, ls.set(l)("bye")) } diff --git a/core/src/test/scala/shapeless/monoid.scala b/core/src/test/scala/shapeless/monoid.scala index 3f001ef8b..32eaae372 100644 --- a/core/src/test/scala/shapeless/monoid.scala +++ b/core/src/test/scala/shapeless/monoid.scala @@ -89,8 +89,8 @@ class MonoidTests { @Test def testBasics: Unit = { - implicit val fooInstance = Monoid[Foo] - implicit val barInstance = Monoid[Bar] + implicit val fooInstance: Monoid[Foo] = Monoid.deriveInstance + implicit val barInstance: Monoid[Bar] = Monoid.deriveInstance val f = Foo(13, "foo") |+| Foo(23, "bar") assertEquals(Foo(36, "foobar"), f) diff --git a/core/src/test/scala/shapeless/poly.scala b/core/src/test/scala/shapeless/poly.scala index b0dd6cfa8..61859da7b 100644 --- a/core/src/test/scala/shapeless/poly.scala +++ b/core/src/test/scala/shapeless/poly.scala @@ -61,18 +61,18 @@ object get extends (Option ~> Id) { /** Polymorphic addition with type specific cases. */ object plus extends Poly2 { - implicit val caseInt = at[Int, Int](_ + _) - implicit val caseDouble = at[Double, Double](_ + _) - implicit val caseString = at[String, String](_ + _) - implicit def caseList[T] = at[List[T], List[T]](_ ::: _) + implicit val caseInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) + implicit val caseDouble: Case.Aux[Double, Double, Double] = at[Double, Double](_ + _) + implicit val caseString: Case.Aux[String, String, String] = at[String, String](_ + _) + implicit def caseList[T]: Case.Aux[List[T], List[T], List[T]] = at[List[T], List[T]](_ ::: _) } /** Polymorphic zero with type specific cases. */ object zero extends Poly0 { - implicit val zeroInt = at(0) - implicit val zeroDouble = at(0.0) - implicit val zeroString = at("") - implicit def zeroList[T] = at[List[T]](Nil) + implicit val zeroInt: Case0[Int] = at(0) + implicit val zeroDouble: Case0[Double] = at(0.0) + implicit val zeroString: Case0[String] = at("") + implicit def zeroList[T]: Case0[List[T]] = at[List[T]](Nil) } class PolyTests { @@ -81,12 +81,12 @@ class PolyTests { } object size extends Poly1 { - implicit def default[T] = at[T](_ => 1) - implicit def caseInt = at[Int](_ => 1) - implicit def caseString = at[String](_.length) - implicit def caseList[T] = at[List[T]](_.length) - implicit def caseOption[T](implicit st : Case.Aux[T, Int]) = at[Option[T]](t => 1+(t map size).getOrElse(0)) - implicit def caseTuple[T, U](implicit st : Case.Aux[T, Int], su : Case.Aux[U, Int]) = at[(T, U)]{ case (t, u) => size(t)+size(u) } + implicit def default[T]: Case.Aux[T, Int] = at[T](_ => 1) + implicit def caseInt: Case.Aux[Int, Int] = at[Int](_ => 1) + implicit def caseString: Case.Aux[String, Int] = at[String](_.length) + implicit def caseList[T]: Case.Aux[List[T], Int] = at[List[T]](_.length) + implicit def caseOption[T](implicit st : Case.Aux[T, Int]): Case.Aux[Option[T], Int] = at[Option[T]](t => 1+(t map size).getOrElse(0)) + implicit def caseTuple[T, U](implicit st : Case.Aux[T, Int], su : Case.Aux[U, Int]): Case.Aux[(T, U), Int] = at[(T, U)]{ case (t, u) => size(t)+size(u) } } @Test @@ -269,8 +269,8 @@ class PolyTests { // Polymophic function value with type-specific cases for two // argument types. Result type is dependent on argument type object bidi extends Poly1 { - implicit val caseInt = at[Int](_.toString) - implicit val caseString = at[String](_.toInt) + implicit val caseInt: Case.Aux[Int, String] = at[Int](_.toString) + implicit val caseString: Case.Aux[String, Int] = at[String](_.toInt) } @Test @@ -292,11 +292,11 @@ class PolyTests { @Test def testRotateLeft: Unit = { object isd extends Poly3 { - implicit val default = at[Int, String, Double] { + implicit val default: Case.Aux[Int, String, Double, String] = at[Int, String, Double] { case (i, s, d) => s"i: $i, s: $s, d: $d" } - implicit val another = at[Long, Char, Boolean] { + implicit val another: Case.Aux[Long, Char, Boolean, String] = at[Long, Char, Boolean] { case (l, c, b) => s"l: $l, c: $c, b: $b" } } @@ -321,7 +321,7 @@ class PolyTests { assertTypedEquals[String](s"i: 1, s: foo, d: ${2.0}", r3) object isdc extends Poly4 { - implicit val default = at[Int, String, Double, Char] { + implicit val default: Case.Aux[Int, String, Double, Char, String] = at[Int, String, Double, Char] { case (i, s, d, c) => s"i: $i, s: $s, d: $d, c: $c" } } @@ -343,7 +343,7 @@ class PolyTests { @Test def testRotateRight: Unit = { object isd extends Poly3 { - implicit val default = at[Int, String, Double] { + implicit val default: Case.Aux[Int, String, Double, String] = at[Int, String, Double] { case (i, s, d) => s"i: $i, s: $s, d: $d" } } @@ -362,7 +362,7 @@ class PolyTests { assertTypedEquals[String](s"i: 1, s: foo, d: ${2.0}", r3) object isdc extends Poly4 { - implicit val default = at[Int, String, Double, Char] { + implicit val default: Case.Aux[Int, String, Double, Char, String] = at[Int, String, Double, Char] { case (i, s, d, c) => s"i: $i, s: $s, d: $d, c: $c" } } @@ -433,7 +433,7 @@ class PolyTests { @Test def testBindFirst: Unit = { object p extends Poly3 { - implicit def x = at[Int, String, Double] { (i, s, d) => + implicit def x: Case.Aux[Int, String, Double, String] = at[Int, String, Double] { (i, s, d) => s"$i, $d, $s" } } @@ -449,7 +449,7 @@ class PolyTests { @Test def testCurried: Unit = { object p extends Poly3 { - implicit def x = at[Int, Double, String] { (i, d, s) => + implicit def x: Case.Aux[Int, Double, String, String] = at[Int, Double, String] { (i, d, s) => s"$i, $d, $s" } } diff --git a/core/src/test/scala/shapeless/product.scala b/core/src/test/scala/shapeless/product.scala index 47078fc9c..c9e669777 100644 --- a/core/src/test/scala/shapeless/product.scala +++ b/core/src/test/scala/shapeless/product.scala @@ -6,6 +6,7 @@ import testutil._ import syntax.std.product._ import record._ +import labelled.->> class ProductTests { @@ -144,14 +145,14 @@ class ProductTests { // With explicit type arguments, >: or =:= to the inferred ones respectively { - val fooL = foo.toRecord[Record.`"i" -> AnyVal, "s" -> String`.T] + val fooL = foo.toRecord[("i" ->> AnyVal) :: ("s" ->> String) :: HNil] val expectedFooL = Record(i=1: AnyVal, s="b") equalInferredTypes(expectedFooL, fooL) assertTypedEquals(expectedFooL, fooL) } { - val barL = bar.toRecord[Record.`"b" -> Boolean, "f" -> Foo`.T] + val barL = bar.toRecord[("b" ->> Boolean) :: ("f" ->> Foo) :: HNil] val expectedBarL = Record(b=true, f=foo) equalInferredTypes(expectedBarL, barL) assertTypedEquals(expectedBarL, barL) diff --git a/core/src/test/scala/shapeless/records.scala b/core/src/test/scala/shapeless/records.scala index 89527f44e..8526df7d2 100644 --- a/core/src/test/scala/shapeless/records.scala +++ b/core/src/test/scala/shapeless/records.scala @@ -43,9 +43,9 @@ class RecordTests { case class Bar(a: Int, b: String) - type MapRec = Record.`"map" -> Map[String, Int]`.T - type TupleRec = Record.`"tuple" -> (String, Int)`.T - type ComplexRec = Record.`"map" -> Map[String, Int], "tuple" -> (String, Int)`.T + type MapRec = ("map" ->> Map[String, Int]) :: HNil + type TupleRec = ("tuple" ->> (String, Int)) :: HNil + type ComplexRec = ("map" ->> Map[String, Int]) :: ("tuple" ->> (String, Int)) :: HNil @Test def testGet: Unit = { @@ -143,7 +143,7 @@ class RecordTests { @Test def testFromMap: Unit = { - type T1 = Record.`"stringVal" -> String, "intVal" -> Int, "boolVal" -> Boolean`.T + type T1 = ("stringVal" ->> String) :: ("intVal" ->> Int) :: ("boolVal" ->> Boolean) :: HNil val in = Map("intVal" -> 4, "stringVal" -> "Blarr", "boolVal" -> true) @@ -309,7 +309,7 @@ class RecordTests { val rExp = "a" ->> 13 :: "b" ->> "foo" :: "c" ->> false :: HNil val rm = r1.merge(r2) - typed[Record.`"a" -> Int, "b" -> String, "c" -> Boolean`.T](rm) + typed[("a" ->> Int) :: ("b" ->> String) :: ("c" ->> Boolean) :: HNil](rm) assertEquals(rExp, rm) } @@ -356,17 +356,17 @@ class RecordTests { val inner1 = Record(d = 3, m = 2D, x= "X") val outer1 = Record(x = "foo", d = -1, e = inner1) - type i = Record.`"x" -> String, "d" -> Int`.T - type i1 = Record.`"x" -> Any, "d" -> Any`.T + type i = ("x" ->> String) :: ("d" ->> Int) :: HNil + type i1 = ("x" ->> Any) :: ("d" ->> Any) :: HNil val extRes = Record(e = Record(x = "X", d = 3), d = -1) - assertTypedEquals(extRes)(outer1.extract[Record.`"e" -> i, "d" -> Int`.T]) + assertTypedEquals(extRes)(outer1.extract[("e" ->> i) :: ("d" ->> Int) :: HNil]) //covariance - assertEquals(extRes, outer1.extract[Record.`"e" -> i1, "d" -> Any`.T]) + assertEquals(extRes, outer1.extract[("e" ->> i1) :: ("d" ->> Any) :: HNil]) - type ill1 = Record.`"d" -> Int, "z" -> Int`.T - type ill2 = Record.`"x" -> i`.T - type illIner = Record.`"m" -> String, "d" -> Int`.T - type ill3 = Record.`"e" -> illIner, "d" -> Int`.T + type ill1 = ("d" ->> Int) :: ("z" ->> Int) :: HNil + type ill2 = ("x" ->> i) :: HNil + type illIner = ("m" ->> String) :: ("d" ->> Int) :: HNil + type ill3 = ("e" ->> illIner) :: ("d" ->> Int) :: HNil illTyped("outer1.extract[ill1]") @@ -377,8 +377,8 @@ class RecordTests { @Test def testMergeWith: Unit = { object mergeField extends Poly2 { - implicit def xor = at[Boolean, Boolean] { _ ^ _ } - implicit def toDouble = at[Int, String] { _.toDouble + _.toDouble } + implicit def xor: Case.Aux[Boolean, Boolean, Boolean] = at[Boolean, Boolean] { _ ^ _ } + implicit def toDouble: Case.Aux[Int, String, Double] = at[Int, String] { _.toDouble + _.toDouble } } { @@ -387,7 +387,7 @@ class RecordTests { val rExp = "c" ->> true :: HNil val rm = r1.mergeWith(r2)(mergeField) - typed[Record.`"c" -> Boolean`.T](rm) + typed[("c" ->> Boolean) :: HNil](rm) assertEquals(rExp, rm) } @@ -397,7 +397,7 @@ class RecordTests { val rExp = "a" ->> 36.0 :: "b" ->> "foo" :: "c" ->> true :: HNil val rm = r1.mergeWith(r2)(mergeField) - typed[Record.`"a" -> Double, "b" -> String, "c" -> Boolean`.T](rm) + typed[("a" ->> Double) :: ("b" ->> String) :: ("c" ->> Boolean) :: HNil](rm) assertEquals(rExp, rm) } } @@ -579,7 +579,7 @@ class RecordTests { @Test def testReplace: Unit = { - type R = Record.`"a" -> Int, "b" -> String`.T + type R = ("a" ->> Int) :: ("b" ->> String) :: HNil val a = Record(a = 1, b = "2") val r = a.replace("a", 2) @@ -593,8 +593,8 @@ class RecordTests { def testLacksKey: Unit = { def without[R <: HList, O <: HList, K <: Singleton](k: K)(r: R)(f: R => O)(implicit ev: LacksKey[R, K]): O = f(r) - type R1 = Record.`"a" -> Int, "b" -> String, "c" -> Boolean`.T - type R2 = Record.`"c" -> Boolean, "a" -> Int, "b" -> String`.T + type R1 = ("a" ->> Int) :: ("b" ->> String) :: ("c" ->> Boolean) :: HNil + type R2 = ("c" ->> Boolean) :: ("a" ->> Int) :: ("b" ->> String) :: HNil val a = Record(a = 1, b = "2") @@ -611,13 +611,13 @@ class RecordTests { @Test def testRemoveAll: Unit = { - type R = Record.`"i" -> Int, "s" -> String, "c" -> Char, "j" -> Int`.T - type L = Record.`"c" -> Char, "j" -> Int`.T - type L2 = Record.`"s" -> String, "c" -> Char`.T + type R = ("i" ->> Int) :: ("s" ->> String) :: ("c" ->> Char) :: ("j" ->> Int) :: HNil + type L = ("c" ->> Char) :: ("j" ->> Int) :: HNil + type L2 = ("s" ->> String) :: ("c" ->> Char) :: HNil - type A1 = Record.`"i" -> Int, "s" -> String`.T + type A1 = ("i" ->> Int) :: ("s" ->> String) :: HNil type A2 = Int :: String :: HNil - type A3 = Record.`"i" -> Int, "j" -> Int`.T + type A3 = ("i" ->> Int) :: ("j" ->> Int) :: HNil type A4 = Int :: Int :: HNil val r = "i" ->> 10 :: "s" ->> "foo" :: "c" ->> 'x' :: "j" ->> 42 :: HNil @@ -677,11 +677,11 @@ class RecordTests { @Test def testMappingOverRecordFields: Unit = { object toUpper extends Poly1 { - implicit def stringToUpper[F] = at[FieldType[F, String]] { + implicit def stringToUpper[F]: Case.Aux[FieldType[F, String], FieldType[F, String]] = at[FieldType[F, String]] { f => field[F](f.toUpperCase) } - implicit def otherTypes[X] = at[X](identity) + implicit def otherTypes[X]: Case.Aux[X, X] = at[X](identity) } val r = ("foo" ->> "joe") :: ("bar" ->> true) :: ("baz" ->> 2.0) :: HNil @@ -775,16 +775,14 @@ class RecordTests { import poly._ object f extends FieldPoly { - implicit def atFoo = atField[Int]("foo")(_ + 1) + implicit def atFoo = atField[Int, "foo"]("foo")(_ + 1) } val r = "foo" ->> 23 val r1 = f(r) - val fooType = "foo".witness - - typed[FieldType[fooType.T, Int]](r1) + typed[FieldType["foo", Int]](r1) assertEquals(24, r1) } @@ -794,7 +792,7 @@ class RecordTests { import poly._ object f extends FieldPoly { - implicit def atFoo = atField[Int]("foo")(_ + 1) + implicit def atFoo = atField[Int, "foo"]("foo")(_ + 1) } val r = ("foo" ->> 23) :: ("bar" ->> true) :: HNil @@ -815,7 +813,7 @@ class RecordTests { import poly._ object f extends FieldPoly { - implicit def atFoo = atField[Int]("foo")(_ + 1) + implicit def atFoo = atField[Int, "foo"]("foo")(_ + 1) } val r = List(List(List(("foo" ->> 23) :: ("bar" ->> true) :: HNil))) @@ -849,25 +847,25 @@ class RecordTests { @Test def testRecordTypeSelector: Unit = { - typed[Record.` `.T](HNil) + typed[HNil](HNil) - typed[Record.`"i" -> Int`.T]("i" ->> 23 :: HNil) + typed[("i" ->> Int) :: HNil]("i" ->> 23 :: HNil) - typed[Record.`"i" -> Int, "s" -> String`.T]("i" ->> 23 :: "s" ->> "foo" :: HNil) + typed[("i" ->> Int) :: ("s" ->> String) :: HNil]("i" ->> 23 :: "s" ->> "foo" :: HNil) - typed[Record.`"i" -> Int, "s" -> String, "b" -> Boolean`.T]("i" ->> 23 :: "s" ->> "foo" :: "b" ->> true :: HNil) + typed[("i" ->> Int) :: ("s" ->> String) :: ("b" ->> Boolean) :: HNil]("i" ->> 23 :: "s" ->> "foo" :: "b" ->> true :: HNil) // Literal types - typed[Record.`"i" -> 2`.T]("i" ->> 2.narrow :: HNil) + typed[("i" ->> 2) :: HNil]("i" ->> 2.narrow :: HNil) - typed[Record.`"i" -> 2, "s" -> "a", "b" -> true`.T]("i" ->> 2.narrow :: "s" ->> "a".narrow :: "b" ->> true.narrow :: HNil) + typed[("i" ->> 2) :: ("s" ->> "a") :: ("b" ->> true) :: HNil]("i" ->> 2.narrow :: "s" ->> "a".narrow :: "b" ->> true.narrow :: HNil) - illTyped("""typed[Record.`"i" -> 2`.T]("i" ->> 3.narrow :: HNil)""") + illTyped("""typed[("i" ->> 2) :: HNil]("i" ->> 3.narrow :: HNil)""") // Mix of standard and literal types - typed[Record.`"i" -> 2, "s" -> String, "b" -> true`.T]("i" ->> 2.narrow :: "s" ->> "a" :: "b" ->> true.narrow :: HNil) + typed[("i" ->> 2) :: ("s" ->> String) :: ("b" ->> true) :: HNil]("i" ->> 2.narrow :: "s" ->> "a" :: "b" ->> true.narrow :: HNil) } @Test @@ -876,7 +874,7 @@ class RecordTests { typed[HNil](r1) val r2 = Record(i = 23, s = "foo", b = true) - typed[Record.`"i" -> Int, "s" -> String, "b" -> Boolean`.T](r2) + typed[("i" ->> Int) :: ("s" ->> String) :: ("b" ->> Boolean) :: HNil](r2) illTyped("""Record(2, "a")""") } @@ -900,60 +898,6 @@ class RecordTests { illTyped("""r.get("foo")""") } - object Foo extends RecordArgs { - def applyRecord[R <: HList](rec: R): R = rec - } - - @Test - def testRecordArgs: Unit = { - val r = Foo(i = 23, s = "foo", b = true) - typed[Record.`"i" -> Int, "s" -> String, "b" -> Boolean`.T](r) - - val v1 = r.get("i") - typed[Int](v1) - assertEquals(23, v1) - - val v2 = r.get("s") - typed[String](v2) - assertEquals("foo", v2) - - val v3 = r.get("b") - typed[Boolean](v3) - assertEquals(true, v3) - - illTyped("""r.get("foo")""") - } - - object Bar extends FromRecordArgs { - def sum(i1: Int, i2: Int) = i1 + i2 - def sumImplicit(i1: Int)(implicit i2: Int) = i1 + i2 - def sumMultipleParamList(i1: Int)(i2: Int) = i1 + i2 - } - - @Test - def testFromRecordArgs: Unit = { - val r = ("i1" ->> 1) :: ("i2" ->> 3) :: HNil - - val v1 = Bar.sumRecord(r) - typed[Int](v1) - assertEquals(4, v1) - - val r2 = r.merge(("i2" ->> 2) :: HNil) - val v2 = Bar.sumMultipleParamListRecord(r2) - typed[Int](v2) - assertEquals(3, v2) - - illTyped("""Bar.sumImplicitRecord(("i1" ->> 1) :: ("i2" ->> 3) :: HNil)""") - - implicit val i2 = 7 - val v3 = Bar.sumImplicitRecord(r) - typed[Int](v2) - assertEquals(8, v3) - - illTyped("""Bar.sumRecord(("i1" ->> 1) :: ("i3" ->> 3) :: HNil)""") - illTyped("""Bar.sumMultipleParamListRecord(("i1" ->> 1) :: ("i3" ->> 3) :: HNil)""") - } - @Test def testFields: Unit = { { @@ -995,7 +939,7 @@ class RecordTests { assertTypedEquals(HNil: HNil, uf.values(HNil: HNil)) } - type R = Record.`"i" -> Int, "s" -> String, "b" -> Boolean`.T + type R = ("i" ->> Int) :: ("s" ->> String) :: ("b" ->> Boolean) :: HNil val r: R = Record(i = 23, s = "foo", b = true) { @@ -1004,7 +948,7 @@ class RecordTests { assertTypedEquals(23 :: "foo" :: true :: HNil, uf.values(r)) } - type RS = Record.`"first" -> Option[Int], "second" -> Option[Boolean], "third" -> Option[String]`.T + type RS = ("first" ->> Option[Int]) :: ("second" ->> Option[Boolean]) :: ("third" ->> Option[String]) :: HNil val rs: RS = ("first" ->> Some(2)) :: ("second" ->> Some(true)) :: ("third" ->> Option.empty[String]) :: HNil { @@ -1059,9 +1003,9 @@ class RecordTests { @Test def testMapValues: Unit = { object f extends Poly1 { - implicit def int = at[Int](i => i > 0) - implicit def string = at[String](s => s"s: $s") - implicit def boolean = at[Boolean](v => if (v) "Yup" else "Nope") + implicit def int: Case.Aux[Int, Boolean] = at[Int](i => i > 0) + implicit def string: Case.Aux[String, String] = at[String](s => s"s: $s") + implicit def boolean: Case.Aux[Boolean, String] = at[Boolean](v => if (v) "Yup" else "Nope") } { @@ -1073,13 +1017,13 @@ class RecordTests { { val r = Record(i = 23, s = "foo", b = true) val res = r.mapValues(f) - assertTypedEquals[Record.`"i" -> Boolean, "s" -> String, "b" -> String`.T](Record(i = true, s = "s: foo", b = "Yup"), res) + assertTypedEquals[("i" ->> Boolean) :: ("s" ->> String) :: ("b" ->> String) :: HNil](Record(i = true, s = "s: foo", b = "Yup"), res) } { object toUpper extends Poly1 { - implicit def stringToUpper = at[String](_.toUpperCase) - implicit def otherTypes[X] = at[X](identity) + implicit def stringToUpper: Case.Aux[String, String] = at[String](_.toUpperCase) + implicit def otherTypes[X]: Case.Aux[X, X] = at[X](identity) } val r = ("foo" ->> "joe") :: ("bar" ->> true) :: ("baz" ->> 2.0) :: HNil @@ -1103,7 +1047,7 @@ class RecordTests { def testSwapRecord: Unit = { import shapeless.ops.record.SwapRecord - type TestRecord = "x" ->> Int :: "y" ->> String :: "z" -> Boolean :: HNil + type TestRecord = ("x" ->> Int) :: ("y" ->> String) :: ("z" ->> Boolean) :: HNil val fields: (FieldType[Int, "x"] :: FieldType[String, "y"] :: FieldType[Boolean, "z"] :: HNil) = SwapRecord[TestRecord].apply() @@ -1112,20 +1056,20 @@ class RecordTests { @Test def alignByKeys: Unit = { - type TestRecord = Record.`"a" -> String, "b" -> Int, "c" -> Double`.T + type TestRecord = ("a" ->> String) :: ("b" ->> Int) :: ("c" ->> Double) :: HNil - type Keys1 = HList.`"a", "b", "c"`.T - type Keys2 = HList.`"b", "c", "a"`.T - type Keys3 = HList.`"b", "a", "c"`.T - type Keys4 = HList.`"c", "a", "b"`.T + type Keys1 = "a" :: "b" :: "c" :: HNil + type Keys2 = "b" :: "c" :: "a" :: HNil + type Keys3 = "b" :: "a" :: "c" :: HNil + type Keys4 = "c" :: "a" :: "b" :: HNil val v = Record(a = "foo", b = 42, c = 33.3) assertTypedEquals[TestRecord](v, AlignByKeys[TestRecord, Keys1].apply(v)) - assertTypedEquals[Record.`"b" -> Int, "c" -> Double, "a" -> String`.T](Record(b = 42, c = 33.3, a = "foo"), AlignByKeys[TestRecord, Keys2].apply(v)) + assertTypedEquals[("b" ->> Int) :: ("c" ->> Double) :: ("a" ->> String) :: HNil](Record(b = 42, c = 33.3, a = "foo"), AlignByKeys[TestRecord, Keys2].apply(v)) - assertTypedEquals[Record.`"b" -> Int, "a" -> String, "c" -> Double`.T](Record(b = 42, a = "foo", c = 33.3), v.alignByKeys[Keys3]) - assertTypedEquals[Record.`"c" -> Double, "a" -> String, "b" -> Int`.T](Record(c = 33.3, a = "foo", b = 42), v.alignByKeys[Keys4]) + assertTypedEquals[("b" ->> Int) :: ("a" ->> String) :: ("c" ->> Double) :: HNil](Record(b = 42, a = "foo", c = 33.3), v.alignByKeys[Keys3]) + assertTypedEquals[("c" ->> Double) :: ("a" ->> String) :: ("b" ->> Int) :: HNil](Record(c = 33.3, a = "foo", b = 42), v.alignByKeys[Keys4]) } @Test diff --git a/core/src/test/scala/shapeless/singletons.scala b/core/src/test/scala/shapeless/singletons.scala index 60b14e399..e9e3259f3 100644 --- a/core/src/test/scala/shapeless/singletons.scala +++ b/core/src/test/scala/shapeless/singletons.scala @@ -83,15 +83,15 @@ class SingletonTypesTests { } object Show { - implicit val showTrue = new Show[True] { def show = "true" } - implicit val showFalse = new Show[False] { def show = "false" } + implicit val showTrue: Show[True] = new Show[True] { def show = "true" } + implicit val showFalse: Show[False] = new Show[False] { def show = "false" } - implicit val showOne = new Show[_1] { def show = "One" } - implicit val showTwo = new Show[_2] { def show = "Two" } - implicit val showThree = new Show[_3] { def show = "Three" } + implicit val showOne: Show[_1] = new Show[_1] { def show = "One" } + implicit val showTwo: Show[_2] = new Show[_2] { def show = "Two" } + implicit val showThree: Show[_3] = new Show[_3] { def show = "Three" } - implicit val showFoo = new Show[Foo] { def show = "'foo" } - implicit val showBar = new Show[Bar] { def show = "'bar" } + implicit val showFoo: Show[Foo] = new Show[Foo] { def show = "'foo" } + implicit val showBar: Show[Bar] = new Show[Bar] { def show = "'bar" } } def show[T](t: T)(implicit s: Show[T]) = s.show @@ -127,15 +127,15 @@ class SingletonTypesTests { } object LiteralShow { - implicit val showTrue = new LiteralShow[true] { def show = "true" } - implicit val showFalse = new LiteralShow[false] { def show = "false" } + implicit val showTrue: LiteralShow[true] = new LiteralShow[true] { def show = "true" } + implicit val showFalse: LiteralShow[false] = new LiteralShow[false] { def show = "false" } - implicit val showOne = new LiteralShow[1] { def show = "One" } - implicit val showTwo = new LiteralShow[2] { def show = "Two" } - implicit val showThree = new LiteralShow[3] { def show = "Three" } + implicit val showOne: LiteralShow[1] = new LiteralShow[1] { def show = "One" } + implicit val showTwo: LiteralShow[2] = new LiteralShow[2] { def show = "Two" } + implicit val showThree: LiteralShow[3] = new LiteralShow[3] { def show = "Three" } - implicit val showFoo = new LiteralShow["foo"] { def show = "'foo" } - implicit val showBar = new LiteralShow["bar"] { def show = "'bar" } + implicit val showFoo: LiteralShow["foo"] = new LiteralShow["foo"] { def show = "'foo" } + implicit val showBar: LiteralShow["bar"] = new LiteralShow["bar"] { def show = "'bar" } } def literalShow[T](t: T)(implicit s: LiteralShow[T]) = s.show @@ -171,9 +171,9 @@ class SingletonTypesTests { } object LiteralsShow { - implicit val showTrueFalse = new LiteralsShow[HList.`true, false`.T] { def show = "true, false" } - implicit val showOneOrTwoOrThree = new LiteralsShow[Coproduct.`1, 2, 3`.T] { def show = "One | Two | Three" } - implicit val showFooBar = new LiteralsShow[HList.`"foo", "bar"`.T] { def show = "'foo, 'bar" } + implicit val showTrueFalse: LiteralsShow[true :: false :: HNil] = new LiteralsShow[true :: false :: HNil] { def show = "true, false" } + implicit val showOneOrTwoOrThree: LiteralsShow[1 :+: 2 :+: 3 :+: CNil] = new LiteralsShow[1 :+: 2 :+: 3 :+: CNil] { def show = "One | Two | Three" } + implicit val showFooBar: LiteralsShow["foo" :: "bar" :: HNil] = new LiteralsShow["foo" :: "bar" :: HNil] { def show = "'foo, 'bar" } } def literalsShow[T](t: T)(implicit s: LiteralsShow[T]) = s.show @@ -294,23 +294,6 @@ class SingletonTypesTests { illTyped("Widen[A.type]", "could not find implicit value for parameter widen:.*") } - @Test - def testWitnessThisType: Unit = { - class ClassThis { - val w1 = Witness(this) - val w2 = Witness.of[this.type] - } - - object ObjectThis { - val w1 = Witness(this) - val w2 = Witness.of[this.type] - } - - val c = new ClassThis - assertTypedEquals[c.type](c.w1.value, c.w2.value) - assertTypedEquals[ObjectThis.type](ObjectThis.w1.value, ObjectThis.w2.value) - } - @Test def testWitnessTypeRefType: Unit = { trait B1 { @@ -324,45 +307,6 @@ class SingletonTypesTests { assertTypedEquals[A.type](A1().getT, A) } - - class NestingBug { - val o: AnyRef = new Object {} - - val wO = { - final class W extends ValueOf[o.type](o) - new W - } - - val x1: o.type = wO.value - } - - class PathDependentSingleton1 { - val o: AnyRef = new Object {} - val wO = Witness(o) - type OT = wO.T - implicitly[OT =:= o.type] - - val x0: OT = wO.value - val x1: o.type = wO.value - - val x2 = wO.value - typed[o.type](x2) - typed[OT](x2) - } - - object PathDependentSingleton2 { - val o: AnyRef = new Object {} - val wO = Witness(o) - type OT = wO.T - implicitly[OT =:= o.type] - - val x0: OT = wO.value - val x1: o.type = wO.value - - val x2 = wO.value - typed[o.type](x2) - typed[OT](x2) - } } package SingletonTypeTestsAux { @@ -372,7 +316,7 @@ package SingletonTypeTestsAux { case object A extends Sealed } - implicitly[Witness.Aux[Sealed.A.type]] + implicitly[ValueOf[Sealed.A.type]] } } @@ -425,9 +369,9 @@ object VarArgsWitnessTest { object instance extends Base val dep = new Dep[instance.type] - def varargs[B <: Base with Singleton](el: Dep[B]*)(implicit w: Witness.Aux[B]): Unit = () - def poly[B <: Base with Singleton](el1: Dep[B])(implicit w: Witness.Aux[B]): Unit = () - def poly[B <: Base with Singleton](el1: Dep[B], el2: Dep[B])(implicit w: Witness.Aux[B]): Unit = () + def varargs[B <: Base with Singleton](el: Dep[B]*)(implicit w: ValueOf[B]): Unit = () + def poly[B <: Base with Singleton](el1: Dep[B])(implicit w: ValueOf[B]): Unit = () + def poly[B <: Base with Singleton](el1: Dep[B], el2: Dep[B])(implicit w: ValueOf[B]): Unit = () varargs(dep) varargs(dep, dep) @@ -438,7 +382,7 @@ object VarArgsWitnessTest { object RefinedWithSingletonTypeWitnessTest { import nat._ - implicitly[Witness { type T = _0 }] - implicitly[Witness { type T = _1 }] - implicitly[Witness { type T = None.type }] + implicitly[ValueOf[_0]] + implicitly[ValueOf[_1]] + implicitly[ValueOf[None.type]] } diff --git a/core/src/test/scala/shapeless/sybclass.scala b/core/src/test/scala/shapeless/sybclass.scala index 137955ab3..c03bc88c7 100644 --- a/core/src/test/scala/shapeless/sybclass.scala +++ b/core/src/test/scala/shapeless/sybclass.scala @@ -23,37 +23,37 @@ import shapeless.test._ class SybClassTests { trait gsizeAll0 extends Poly1 { - implicit def default[T](implicit data: Data[this.type, T, Int]) = + implicit def default[T](implicit data: Data[this.type, T, Int]): Case.Aux[T, Int] = at[T](data.gmapQ(_).sum + 1) } object gsizeAll extends gsizeAll0 { - implicit def caseString = at[String](_.length) + implicit def caseString: Case.Aux[String, Int] = at[String](_.length) } trait gsize0 extends Poly1 { - implicit def default[T] = at[T](_ => 1) + implicit def default[T]: Case.Aux[T, Int] = at[T](_ => 1) } object gsize extends gsize0 { - implicit def caseInt = at[Int](_ => 1) - implicit def caseString = at[String](_.length) + implicit def caseInt: Case.Aux[Int, Int] = at[Int](_ => 1) + implicit def caseString: Case.Aux[String, Int] = at[String](_.length) } def gsizeAll2[T](t: T)(implicit everything: Everything[gsize.type, plus.type, T]) = everything(t) trait incAll0 extends Poly1 { - implicit def default[T](implicit data: DataT.Aux[this.type, T, T]) = + implicit def default[T](implicit data: DataT.Aux[this.type, T, T]): Case.Aux[T, T] = at[T](data.gmapT) } object incAll extends incAll0 { - implicit def caseInt = at[Int](_+1) - implicit def caseString = at[String](_+"*") + implicit def caseInt: Case.Aux[Int, Int] = at[Int](_+1) + implicit def caseString: Case.Aux[String, String] = at[String](_+"*") } object inc extends Poly1 { - implicit def caseInt = at[Int](_+1) - implicit def caseString = at[String](_+"*") + implicit def caseInt: Case.Aux[Int, Int] = at[Int](_+1) + implicit def caseString: Case.Aux[String, String] = at[String](_+"*") } def incAll2[T](t: T)(implicit everywhere: Everywhere[inc.type, T]) = everywhere(t) @@ -65,17 +65,17 @@ class SybClassTests { case class Orange(i: Int) extends Fruit object showFruit extends Poly1 { - implicit def caseApple = at[Apple] (_ => "Pomme") - implicit def casePear = at[Pear] (_ => "Poire") - implicit def caseBanana = at[Banana](_ => "Banane") - implicit def caseOrange = at[Orange](_ => "Orange") + implicit def caseApple: Case.Aux[Apple, String] = at[Apple] (_ => "Pomme") + implicit def casePear: Case.Aux[Pear, String] = at[Pear] (_ => "Poire") + implicit def caseBanana: Case.Aux[Banana, String] = at[Banana](_ => "Banane") + implicit def caseOrange: Case.Aux[Orange, String] = at[Orange](_ => "Orange") } object cycleFruit extends Poly1 { - implicit def caseApple = at[Apple] { case Apple(i) => Pear(i) } - implicit def casePear = at[Pear] { case Pear(i) => Banana(i) } - implicit def caseBanana = at[Banana]{ case Banana(i) => Orange(i) } - implicit def caseOrange = at[Orange]{ case Orange(i) => Apple(i) } + implicit def caseApple: Case.Aux[Apple, Pear] = at[Apple] { case Apple(i) => Pear(i) } + implicit def casePear: Case.Aux[Pear, Banana] = at[Pear] { case Pear(i) => Banana(i) } + implicit def caseBanana: Case.Aux[Banana, Orange] = at[Banana]{ case Banana(i) => Orange(i) } + implicit def caseOrange: Case.Aux[Orange, Apple] = at[Orange]{ case Orange(i) => Apple(i) } } sealed trait Tree[T] @@ -364,8 +364,8 @@ class SybClassTests { case class A(x: Int, y: Boolean, z: Int) object flip extends Poly1 { - implicit def apply[T] = at[T](identity) - implicit def caseBoolean = at[Boolean](!_) + implicit def apply[T]: Case.Aux[T, T] = at[T](identity) + implicit def caseBoolean: Case.Aux[Boolean, Boolean] = at[Boolean](!_) } @Test diff --git a/core/src/test/scala/shapeless/tuples.scala b/core/src/test/scala/shapeless/tuples.scala index 65742c293..fb3e87d52 100644 --- a/core/src/test/scala/shapeless/tuples.scala +++ b/core/src/test/scala/shapeless/tuples.scala @@ -122,17 +122,17 @@ class TupleTests { val m2eim2esm2eim2eem2ed = (m2iExist, m2sExist, m2iExist, m2iExist, m2dExist) trait incInt0 extends Poly1 { - implicit def default[T] = at[T](t => ()) + implicit def default[T]: Case.Aux[T, Unit] = at[T](t => ()) } object incInt extends incInt0 { - implicit val caseInt = at[Int](i => Tuple1(i+1)) + implicit val caseInt: Case.Aux[Int, Tuple1[Int]] = at[Int](i => Tuple1(i+1)) } trait extendedChoose0 extends Poly1 { - implicit def default[T] = at[T](t => ()) + implicit def default[T]: Case.Aux[T, Unit] = at[T](t => ()) } object extendedChoose extends extendedChoose0 { - implicit def caseSet[T] = at[Set[T]](s => Tuple1(s.headOption)) + implicit def caseSet[T]: Case.Aux[Set[T], Tuple1[Option[T]]] = at[Set[T]](s => Tuple1(s.headOption)) } @Test @@ -217,7 +217,7 @@ class TupleTests { } object dup extends Poly1 { - implicit def default[T] = at[T](t => (t, t)) + implicit def default[T]: Case.Aux[T, (T, T)] = at[T](t => (t, t)) } @Test @@ -535,9 +535,6 @@ class TupleTests { type CISBa = Int :+: String :+: Boolean :+: CNil val CISBb = ToCoproduct[PISB] implicitly[CISBa =:= CISBb.Out] - - type CISBc = the.`ToCoproduct[PISB]`.Out - implicitly[CISBa =:= CISBc] } @Test @@ -552,12 +549,6 @@ class TupleTests { type PIISSB = (Int, Int, String, String, Boolean) val SISBb = ToSum[PIISSB] implicitly[CISBa =:= SISBb.Out] - - type SISBc = the.`ToSum[PISB]`.Out - implicitly[CISBa =:= SISBc] - - type SISBd = the.`ToSum[PIISSB]`.Out - implicitly[CISBa =:= SISBd] } @Test @@ -1357,8 +1348,8 @@ class TupleTests { } object combine extends Poly { - implicit def caseCharString = use((c : Char, s : String) => s.indexOf(c)) - implicit def caseIntBoolean = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") + implicit def caseCharString: ProductCase.Aux[Char :: String :: HNil, Int] = use((c : Char, s : String) => s.indexOf(c)) + implicit def caseIntBoolean: ProductCase.Aux[Int :: Boolean :: HNil, String] = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") } @Test @@ -1475,8 +1466,8 @@ class TupleTests { object empty extends Poly1 object complex extends Poly1 { - implicit val caseInt = at[Int](_.toDouble) - implicit val caseString = at[String](_ => 1) + implicit val caseInt: Case.Aux[Int, Double] = at[Int](_.toDouble) + implicit val caseString: Case.Aux[String, Int] = at[String](_ => 1) } { // () collect p @@ -1628,9 +1619,9 @@ class TupleTests { } object smear extends Poly { - implicit val caseIntInt = use((x: Int, y: Int) => x + y) - implicit val caseStringInt = use((x: String, y: Int) => x.toInt + y) - implicit val caseIntString = use((x: Int, y: String) => x + y.toInt) + implicit val caseIntInt: ProductCase.Aux[Int :: Int :: HNil, Int] = use((x: Int, y: Int) => x + y) + implicit val caseStringInt: ProductCase.Aux[String :: Int :: HNil, Int] = use((x: String, y: Int) => x.toInt + y) + implicit val caseIntString: ProductCase.Aux[Int :: String :: HNil, Int] = use((x: Int, y: String) => x + y.toInt) } @Test @@ -1787,7 +1778,7 @@ class TupleTests { @Test def testGrouper: Unit = { object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]) = at[N](_ => toi()) + implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) } def range[R <: HList, OutL <: HList](a: Nat, b: Nat)(implicit @@ -1842,7 +1833,7 @@ class TupleTests { @Test def testGrouper2: Unit = { object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]) = at[N](_ => toi()) + implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) } def range[R <: HList, T, OutL <: HList](a: Nat, b: Nat)(implicit diff --git a/core/src/test/scala/shapeless/typeable.scala b/core/src/test/scala/shapeless/typeable.scala index 2b614b213..471140087 100644 --- a/core/src/test/scala/shapeless/typeable.scala +++ b/core/src/test/scala/shapeless/typeable.scala @@ -596,6 +596,7 @@ class TypeableTests { val one: One = 1 assertEquals("Typeable[Int(1)]", typeableString(one)) + object FooBar type FooBarT = FooBar.type val foobar: FooBarT = FooBar assertEquals("Typeable[FooBar.type]", typeableString(foobar)) diff --git a/core/src/test/scala/shapeless/typeoperators.scala b/core/src/test/scala/shapeless/typeoperators.scala index b7821faa3..5edc3658b 100644 --- a/core/src/test/scala/shapeless/typeoperators.scala +++ b/core/src/test/scala/shapeless/typeoperators.scala @@ -56,7 +56,7 @@ class TypeOperatorTests { case class MyStringOps(s : String) { def mySize = s.size } - implicit val mkOps = MyStringOps + implicit val mkOps: MyStringOps.type = MyStringOps val ms = MyString("foo") @@ -123,23 +123,6 @@ class TypeOperatorTests { typed[Either[String, Double]](bar2.tu) } - @Test - def testTheTypes: Unit = { - val t: the.Foo.T = 23 - typed[Int](t) - - val tu1: Either[Boolean, the.`Bar[Boolean]`.U] = Right(23) - typed[Either[Boolean, Int]](tu1) - - val tu2: Either[String, the.`Bar[String]`.U] = Right(23) - typed[Either[String, Double]](tu2) - } - - @Test - def testTheErrors: Unit = { - illTyped("the.`Ordering[Set[Int]]`.Ops", "No implicit Ordering defined for Set\\[Int].") - } - @Test def testTheQuantifiers: Unit = { def bar0[T, U0](implicit b: Bar[T] { type U = U0 }): Bar[T] { type U = U0 } = { @@ -147,17 +130,8 @@ class TypeOperatorTests { res } - // Note: Slightly different method signature in testTheQuantifiers2 - def bar1[T, U0](implicit b: Bar[T] { type U = U0 }): Option[U0] = { - val res: Option[the.`Bar[T]`.U] = None - res - } - val b0 = bar0[Boolean, Int] typed[Bar[Boolean] { type U = Int }](b0) - - val b1 = bar1[Boolean, Int] - typed[Option[Int]](b1) } @Test @@ -167,68 +141,8 @@ class TypeOperatorTests { res } - def bar1[T, U0](implicit b: Bar[T] { type U = U0 }): Option[b.U] = { - val res: Option[the.`Bar[T]`.U] = None - res - } - val b0 = bar0[Boolean, Int] typed[Bar[Boolean] { type U = Int }](b0) - - val b1 = bar1[Boolean, Int] - typed[Option[Int]](b1) - } - - @Test - def testTypeOf: Unit = { - - val t1: TypeOf.`Foo.mkFoo`.T = 23 - typed[Int](t1) - - val t2: TypeOf.`Foo.mkFoo: Foo`.T = 23 - typed[Int](t2) - - val tu1: Either[Boolean, TypeOf.`Bar.mkBar1: Bar[Boolean]`.U] = Right(23) - typed[Either[Boolean, Int]](tu1) - - val tu2: Either[String, TypeOf.`the.apply: Bar[String]`.U] = Right(23) - typed[Either[String, Double]](tu2) - - val tu3: Either[String, TypeOf.`the[Bar[String]]`.U] = Right(23) - typed[Either[String, Double]](tu3) - - val indexedHList: TypeOf.`Generic[(String, Boolean)].to(("foo", true)).zipWithIndex`.type = { - Generic[(String, Boolean)].to(("foo", true)).zipWithIndex - } - typed[(String, _0) :: (Boolean, Succ[_0]) :: HNil](indexedHList) - - implicit val genBaz: TypeOf.`Generic[Baz]`.type = cachedImplicit - val reprBaz = genBaz.to(Baz(23, "foo")) - typed[Int :: String :: HNil](reprBaz) - } - - @Test - def testRejectBogus: Unit = { - try { - the.Foo - assert(false) - } catch { - case _: Throwable => // OK - } - - //the.Unit // illTyped fails for this expression - - implicit val u2: Unit = () - //the.Unit // illTyped fails for this expression - - //the.Int // illTyped fails for this expression - - implicit val i2: Int = 23 - //the.Int // illTyped fails for this expression - - illTyped(""" - val blah = the.`package wibble` - """) } @Test diff --git a/core/src/test/scala/shapeless/unions.scala b/core/src/test/scala/shapeless/unions.scala index a990d554a..8a85bb9eb 100644 --- a/core/src/test/scala/shapeless/unions.scala +++ b/core/src/test/scala/shapeless/unions.scala @@ -19,7 +19,7 @@ package shapeless import org.junit.Test import org.junit.Assert._ -import labelled.FieldType +import labelled.{FieldType, ->>} import union._ import syntax.singleton._ import test._ @@ -34,7 +34,7 @@ class UnionTests { type s = "s" type b = "b" - type U = "i" ->> Int :+: "s" ->> String :+: "b" ->> Boolean :+: CNil + type U = ("i" ->> Int) :+: ("s" ->> String) :+: ("b" ->> Boolean) :+: CNil @Test def testGetLiterals: Unit = { @@ -89,28 +89,22 @@ class UnionTests { @Test def testUnionTypeSelector: Unit = { type ii = FieldType[i, Int] :+: CNil - typed[ii](Coproduct[Union.`"i" -> Int`.T]("i" ->> 23)) + typed[ii](Coproduct[("i" ->> Int) :+: CNil]("i" ->> 23)) type iiss = FieldType[i, Int] :+: FieldType[s, String] :+: CNil - typed[iiss](Coproduct[Union.`"i" -> Int, "s" -> String`.T]("s" ->> "foo")) + typed[iiss](Coproduct[("i" ->> Int) :+: ("s" ->> String) :+: CNil]("s" ->> "foo")) type iissbb = FieldType[i, Int] :+: FieldType[s, String] :+: FieldType[b, Boolean] :+: CNil - typed[iissbb](Coproduct[Union.`"i" -> Int, "s" -> String, "b" -> Boolean`.T]("b" ->> true)) + typed[iissbb](Coproduct[("i" ->> Int) :+: ("s" ->> String) :+: ("b" ->> Boolean) :+: CNil]("b" ->> true)) // Curiously, lines like - // typed[Union.`'i -> Int, 's -> String`.T](Inl('i ->> 23)) + // typed[('i ->> Int) :: ('s ->> String) :: HNil](Inl('i ->> 23)) // or - // val u: Union.`'i -> Int, 's -> String`.T = Inl('i ->> 23) + // val u: ('i ->> Int) :: ('s ->> String) :: HNil = Inl('i ->> 23) // don't compile as is. One has to tear apart the type and the value made of fields and Inl/Inr. { - type U = Union.` `.T - - implicitly[U =:= CNil] - } - - { - type U = Union.`"i" -> Int`.T + type U = ("i" ->> Int) :+: CNil val u = Inl("i" ->> 23) @@ -118,7 +112,7 @@ class UnionTests { } { - type U = Union.`"i" -> Int, "s" -> String`.T + type U = ("i" ->> Int) :+: ("s" ->> String) :+: CNil val u0 = Inl("i" ->> 23) val u1 = Inr(Inl("s" ->> "foo")) @@ -128,7 +122,7 @@ class UnionTests { } { - type U = Union.`"i" -> Int, "s" -> String, "b" -> Boolean`.T + type U = ("i" ->> Int) :+: ("s" ->> String) :+: ("b" ->> Boolean) :+: CNil val u0 = Inl("i" ->> 23) val u1 = Inr(Inl("s" ->> "foo")) @@ -142,7 +136,7 @@ class UnionTests { // Literal types { - type U = Union.`"i" -> 2`.T + type U = ("i" ->> 2) :+: CNil val u = Inl("i" ->> 2.narrow) @@ -150,7 +144,7 @@ class UnionTests { } { - type U = Union.`"i" -> 2, "s" -> "a", "b" -> true`.T + type U = ("i" ->> 2) :+: ("s" ->> "a") :+: ("b" ->> true) :+: CNil val u0 = Inl("i" ->> 2.narrow) val u1 = Inr(Inl("s" ->> "a".narrow)) @@ -162,7 +156,7 @@ class UnionTests { } { - type U = Union.`"i" -> 2`.T + type U = ("i" ->> 2) :+: CNil val u = Inl("i" ->> 3.narrow) @@ -172,7 +166,7 @@ class UnionTests { // Mix of standard and literal types { - type U = Union.`"i" -> 2, "s" -> String, "b" -> true`.T + type U = ("i" ->> 2) :+: ("s" ->> String) :+: ("b" ->> true) :+: CNil val u0 = Inl("i" ->> 2.narrow) val u1 = Inr(Inl("s" ->> "a")) @@ -223,7 +217,7 @@ class UnionTests { assertTypedEquals(Coproduct[UF]("b".narrow -> true), f3) } - type US = Union.`"first" -> Option[Int], "second" -> Option[Boolean], "third" -> Option[String]`.T + type US = ("first" ->> Option[Int]) :+: ("second" ->> Option[Boolean]) :+: ("third" ->> Option[String]) :+: CNil val us1 = Coproduct[US]("first" ->> Option(2)) val us2 = Coproduct[US]("second" ->> Option(true)) val us3 = Coproduct[US]("third" ->> Option.empty[String]) @@ -251,7 +245,7 @@ class UnionTests { { val uf = UnzipFields[U] - type UV = Coproduct.`Int, String, Boolean`.T + type UV = Int :+: String :+: Boolean :+: CNil assertTypedEquals("i".narrow :: "s".narrow :: "b".narrow :: HNil, uf.keys) assertTypedEquals(Coproduct[UV](23), uf.values(u1)) @@ -259,7 +253,7 @@ class UnionTests { assertTypedEquals(Coproduct[UV](true), uf.values(u3)) } - type US = Union.`"first" -> Option[Int], "second" -> Option[Boolean], "third" -> Option[String]`.T + type US = ("first" ->> Option[Int]) :+: ("second" ->> Option[Boolean]) :+: ("third" ->> Option[String]) :+: CNil val us1 = Coproduct[US]("first" ->> Option(2)) val us2 = Coproduct[US]("second" ->> Option(true)) val us3 = Coproduct[US]("third" ->> Option.empty[String]) @@ -267,7 +261,7 @@ class UnionTests { { val uf = UnzipFields[US] - type USV = Coproduct.`Option[Int], Option[Boolean], Option[String]`.T + type USV = Option[Int] :+: Option[Boolean] :+: Option[String] :+: CNil assertTypedEquals("first".narrow :: "second".narrow :: "third".narrow :: HNil, uf.keys) assertTypedEquals(Coproduct[USV](Option(2)), uf.values(us1)) @@ -302,7 +296,7 @@ class UnionTests { assertTypedEquals(Map[String, Any]("b" -> true), m3) } - type US = Union.`"first" -> Option[Int], "second" -> Option[Boolean], "third" -> Option[String]`.T + type US = ("first" ->> Option[Int]) :+: ("second" ->> Option[Boolean]) :+: ("third" ->> Option[String]) :+: CNil val us1 = Coproduct[US]("first" ->> Option(2)) val us2 = Coproduct[US]("second" ->> Option(true)) val us3 = Coproduct[US]("third" ->> Option.empty[String]) @@ -331,9 +325,9 @@ class UnionTests { @Test def testMapValues: Unit = { object f extends Poly1 { - implicit def int = at[Int](i => i > 0) - implicit def string = at[String](s => s"s: $s") - implicit def boolean = at[Boolean](v => if (v) "Yup" else "Nope") + implicit def int: Case.Aux[Int, Boolean] = at[Int](i => i > 0) + implicit def string: Case.Aux[String, String] = at[String](s => s"s: $s") + implicit def boolean: Case.Aux[Boolean, String] = at[Boolean](v => if (v) "Yup" else "Nope") } { @@ -341,7 +335,7 @@ class UnionTests { val u2 = Union[U](s = "foo") val u3 = Union[U](b = true) - type R = Union.`"i" -> Boolean, "s" -> String, "b" -> String`.T + type R = ("i" ->> Boolean) :+: ("s" ->> String) :+: ("b" ->> String) :+: CNil val res1 = u1.mapValues(f) val res2 = u2.mapValues(f) @@ -354,11 +348,11 @@ class UnionTests { { object toUpper extends Poly1 { - implicit def stringToUpper = at[String](_.toUpperCase) - implicit def otherTypes[X] = at[X](identity) + implicit def stringToUpper: Case.Aux[String, String] = at[String](_.toUpperCase) + implicit def otherTypes[X]: Case.Aux[X, X] = at[X](identity) } - type U = Union.`"foo" -> String, "bar" -> Boolean, "baz" -> Double`.T + type U = ("foo" ->> String) :+: ("bar" ->> Boolean) :+: ("baz" ->> Double) :+: CNil val u1 = Coproduct[U]("foo" ->> "joe") val u2 = Coproduct[U]("bar" ->> true) val u3 = Coproduct[U]("baz" ->> 2.0) diff --git a/core/src/test/scala/shapeless/unwrapped.scala b/core/src/test/scala/shapeless/unwrapped.scala index 732b1475d..00430f543 100644 --- a/core/src/test/scala/shapeless/unwrapped.scala +++ b/core/src/test/scala/shapeless/unwrapped.scala @@ -65,7 +65,7 @@ class UnwrappedTests { } type MyString = Newtype[String, MyStringOps] def MyString(s : String) : MyString = newtype(s) - implicit val mkOps = MyStringOps + implicit val mkOps: MyStringOps.type = MyStringOps val pass = the[Pass[MyString]] the[pass.U =:= String] @@ -107,7 +107,7 @@ class UnwrappedTests { } def value[T](t: Tagged[T, _]): T = t.asInstanceOf[T] - implicit def taggedUnwrapped[UI, T, UF](implicit chain: => Unwrapped.Aux[UI, UF]) = + implicit def taggedUnwrapped[UI, T, UF](implicit chain: => Unwrapped.Aux[UI, UF]): Unwrapped.Aux[UI @@ T, UF] = new Unwrapped[UI @@ T] { type U = UF def unwrap(w: UI @@ T) = chain.unwrap(value(w)) @@ -149,7 +149,7 @@ class UnwrappedTests { } type MyString = Newtype[AvWrapper, MyStringOps] def MyString(a: AvWrapper): MyString = newtype(a) - implicit val mkOps = MyStringOps + implicit val mkOps: MyStringOps.type = MyStringOps val ms = MyString(AvWrapper("testing")) diff --git a/examples/src/main/scala/shapeless/examples/alacache.scala b/examples/src/main/scala/shapeless/examples/alacache.scala index 0c83723ee..a0ddc1fee 100644 --- a/examples/src/main/scala/shapeless/examples/alacache.scala +++ b/examples/src/main/scala/shapeless/examples/alacache.scala @@ -37,7 +37,7 @@ import java.util.WeakHashMap * * This uses JUL, but it should be obvious how to use other backends. */ -trait LogFacet extends ProductISOFacet { +trait LogFacet extends ProductISOFacet { outer => trait LogOps extends ProductISOOps { val logger: Logger } @@ -45,7 +45,7 @@ trait LogFacet extends ProductISOFacet { val ops: LogOps trait LogMethods { self: C => - protected def log: Logger = ops.logger + protected def log: Logger = outer.ops.logger } } @@ -128,32 +128,25 @@ trait CachedFacet extends ProductISOFacet { } } -trait CachedCaseClassDefns extends - LogFacet with - CachedFacet with - ProductFacet with - PolymorphicEqualityFacet with - CopyFacet with - ToStringFacet { - - trait CaseClassOps extends - LogOps with - CachedOps with - ProductOps with - PolymorphicEqualityOps with - CopyOps with - ToStringOps - - trait CaseClassCompanion extends - CachedCompanion - - trait CaseClass extends - LogMethods with - CachedMethods with - ProductMethods with - PolymorphicEqualityMethods with - CopyMethods with - ToStringMethods { self: C => } +trait CachedCaseClassDefns extends LogFacet + with CachedFacet + with ProductFacet + with PolymorphicEqualityFacet + with ToStringFacet { + + trait CaseClassOps extends LogOps + with CachedOps + with ProductOps + with PolymorphicEqualityOps + with ToStringOps + + trait CaseClassCompanion extends CachedCompanion + + trait CaseClass extends LogMethods + with CachedMethods + with ProductMethods + with PolymorphicEqualityMethods + with ToStringMethods { self: C => } val ops: CaseClassOps @@ -252,18 +245,6 @@ object ALaCacheDemo extends App { assert(foo.hashCode == foo2.hashCode) assert(foo != foo3) - // copy - val fooCopy = foo.copy() - assert(fooCopy ne foo) - assert(foo == fooCopy) - assert(foo.hashCode == fooCopy.hashCode) - - val mod = Foo(13, "foo") - val fooMod = foo.copy(i = 13) - assert(fooMod ne foo) - assert(mod == fooMod) - assert(mod.hashCode == fooMod.hashCode) - // toString val fooStr = foo.toString assert("Foo(23,foo)" == fooStr) diff --git a/examples/src/main/scala/shapeless/examples/alacarte.scala b/examples/src/main/scala/shapeless/examples/alacarte.scala index ae9147ebd..466677d56 100644 --- a/examples/src/main/scala/shapeless/examples/alacarte.scala +++ b/examples/src/main/scala/shapeless/examples/alacarte.scala @@ -21,10 +21,8 @@ import test._ import scala.reflect.ClassTag -import record._ import ops.hlist.{ Length, Tupler } import ops.nat.ToInt -import ops.record.Merger trait CaseClassFacet { type C @@ -227,18 +225,6 @@ object ALaCarteDemo extends App { assert(foo.hashCode == foo2.hashCode) assert(foo != foo3) - // copy - val fooCopy = foo.copy() - assert(fooCopy ne foo) - assert(foo == fooCopy) - assert(foo.hashCode == fooCopy.hashCode) - - val mod = Foo(13, "foo") - val fooMod = foo.copy(i = 13) - assert(fooMod ne foo) - assert(mod == fooMod) - assert(mod.hashCode == fooMod.hashCode) - // toString val fooStr = foo.toString assert("Foo(23,foo)" == fooStr) diff --git a/examples/src/main/scala/shapeless/examples/backtracking.scala b/examples/src/main/scala/shapeless/examples/backtracking.scala index 5dc7b9229..26c8ad59e 100644 --- a/examples/src/main/scala/shapeless/examples/backtracking.scala +++ b/examples/src/main/scala/shapeless/examples/backtracking.scala @@ -63,16 +63,16 @@ object TypeLevelBacktrack extends App { def apply[A, D](implicit i: IsAncestor[A, D]): IsAncestor[A, D] = i implicit def directFather[A, D] - (implicit e: FatherOf[A, D]) = new IsAncestor[A, D] {} + (implicit e: FatherOf[A, D]): IsAncestor[A, D] = new IsAncestor[A, D] {} implicit def directMother[A, D] - (implicit e: MotherOf[A, D]) = new IsAncestor[A, D] {} + (implicit e: MotherOf[A, D]): IsAncestor[A, D] = new IsAncestor[A, D] {} implicit def fatherSideRelation[A, D, Z] - (implicit e: FatherOf[A, Z], i: IsAncestor[Z, D]) = new IsAncestor[A, D] {} + (implicit e: FatherOf[A, Z], i: IsAncestor[Z, D]): IsAncestor[A, D] = new IsAncestor[A, D] {} implicit def motherSideRelation[A, D, Z] - (implicit e: MotherOf[A, Z], i: IsAncestor[Z, D]) = new IsAncestor[A, D] {} + (implicit e: MotherOf[A, Z], i: IsAncestor[Z, D]): IsAncestor[A, D] = new IsAncestor[A, D] {} } // ------------------------------------------------------------------------- @@ -105,15 +105,15 @@ object TypeLevelBacktrack extends App { // This is used to lower the priority of the *base case*. trait AllAncestorsLowPrio { - implicit def none[Person] = new AllAncestors[Person, HNil] {} + implicit def none[Person]: AllAncestors[Person, HNil] = new AllAncestors[Person, HNil] {} } object AllAncestors extends AllAncestorsLowPrio { implicit def fatherSide[F, P, PA <: HList] - (implicit m: FatherOf[F, P], a: AllAncestors[F, PA]) = new AllAncestors[P, F :: PA] {} + (implicit m: FatherOf[F, P], a: AllAncestors[F, PA]): AllAncestors[P, F :: PA] = new AllAncestors[P, F :: PA] {} implicit def motherSide[M, P, PA <: HList] - (implicit m: MotherOf[M, P], a: AllAncestors[M, PA]) = new AllAncestors[P, M :: PA] {} + (implicit m: MotherOf[M, P], a: AllAncestors[M, PA]): AllAncestors[P, M :: PA] = new AllAncestors[P, M :: PA] {} implicit def bothSides[F, M, P, FA <: HList, MA <: HList, CA <: HList] (implicit @@ -122,7 +122,7 @@ object TypeLevelBacktrack extends App { f: AllAncestors[F, FA], m: AllAncestors[M, MA], p: Prepend.Aux[FA, MA, CA] - ) = new AllAncestors[P, F :: M :: CA] {} + ): _root_.shapeless.examples.TypeLevelBacktrack.AllAncestors[P, F :: M :: CA] = new AllAncestors[P, F :: M :: CA] {} } /** Typeclass witnessing family relationship between [[P2]] and [[P1]]. */ @@ -132,10 +132,10 @@ object TypeLevelBacktrack extends App { def apply[D, A](implicit r: Relationship[D, A]): Relationship[D, A] = r implicit def caseP2AncestorOfP1[P1, P2, A <: HList] - (implicit a: AllAncestors[P1, A], s: Selector[A, P2]) = new Relationship[P1, P2] {} + (implicit a: AllAncestors[P1, A], s: Selector[A, P2]): Relationship[P1, P2] = new Relationship[P1, P2] {} implicit def caseP1AncestorOfP2[P1, P2, A <: HList] - (implicit a: AllAncestors[P2, A], s: Selector[A, P1]) = new Relationship[P1, P2] {} + (implicit a: AllAncestors[P2, A], s: Selector[A, P1]): Relationship[P1, P2] = new Relationship[P1, P2] {} } // Stacy Philip diff --git a/examples/src/main/scala/shapeless/examples/basecopy.scala b/examples/src/main/scala/shapeless/examples/basecopy.scala deleted file mode 100644 index b1b170f28..000000000 --- a/examples/src/main/scala/shapeless/examples/basecopy.scala +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2015 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless.examples - -import shapeless._ - -/** - * Functional update of common fields of a sealed family of case classes - * via a case-class-like copy through the common super type ... - */ -object BaseCopyDemo extends App { - import copySyntax._ - - // Sealed family of case classes ... - sealed trait Base - case class Foo(i: Int, b: Boolean) extends Base - case class Bar(i: Int, s: String, b: Boolean) extends Base - case class Baz(i: Int, b: Boolean, d: Double) extends Base - case class Quux(c: Char, i: Int, b: Boolean) extends Base - - // case class copy style functional update through the common super-type ... - val b1: Base = Foo(23, true) - assert(b1.copy(i = 13) == Foo(13, true)) - - val b2: Base = Bar(23, "foo", false) - assert(b2.copy(i = 13, b = true) == Bar(13, "foo", true)) - - val b3: Base = Baz(23, false, 2.3) - assert(b3.copy(i = 13) == Baz(13, false, 2.3)) - - val b4: Base = Quux('*', 23, false) - assert(b4.copy(b = true, i = 13) == Quux('*', 13, true)) -} - -/** - * Functional update of common fields of an open family of case classes - * via a case-class-like copy through the common super type ... - */ -object OpenBaseCopyDemo extends App { - import openCopySyntax._ - import mergeSyntax._ - - // Open family of case classes ... - trait Base extends OpenFamily[Base] { - val i: Int - val b: Boolean - - case class BaseFields(i: Int, b: Boolean) - def baseFields = BaseFields(i, b) - def baseCopy(base: BaseFields): Base - } - - case class Foo(i: Int, b: Boolean) extends Base { - def baseCopy(base: BaseFields) = this merge base - } - - case class Bar(i: Int, s: String, b: Boolean) extends Base { - def baseCopy(base: BaseFields) = this merge base - } - - case class Baz(i: Int, b: Boolean, d: Double) extends Base { - def baseCopy(base: BaseFields) = this merge base - } - - case class Quux(c: Char, i: Int, b: Boolean) extends Base { - def baseCopy(base: BaseFields) = this merge base - } - - - // case class copy style functional update through the common super-type ... - val b1: Base = Foo(23, true) - assert(b1.copy(i = 13) == Foo(13, true)) - - val b2: Base = Bar(23, "foo", false) - assert(b2.copy(i = 13, b = true) == Bar(13, "foo", true)) - - val b3: Base = Baz(23, false, 2.3) - assert(b3.copy(i = 13) == Baz(13, false, 2.3)) - - val b4: Base = Quux('*', 23, false) - assert(b4.copy(b = true, i = 13) == Quux('*', 13, true)) -} - -// Implementation in terms of RecordArgs, Generic and Lazy ... -object copySyntax { - class CopySyntax[T](t: T) { - object copy extends RecordArgs { - def applyRecord[R <: HList](r: R)(implicit update: UpdateRepr[T, R]): T = update(t, r) - } - } - - implicit def apply[T](t: T): CopySyntax[T] = new CopySyntax[T](t) -} - -object openCopySyntax { - class CopySyntax[T, BaseFields0](t: OpenFamily[T] { type BaseFields = BaseFields0 }) { - object copy extends RecordArgs { - def applyRecord[R <: HList](r: R)(implicit update: UpdateRepr[BaseFields0, R]): T = - t.baseCopy(update(t.baseFields, r)) - } - } - - implicit def apply[T](t: OpenFamily[T]): CopySyntax[T, t.BaseFields] = new CopySyntax(t) -} - -trait OpenFamily[T] { - type BaseFields - def baseFields: BaseFields - def baseCopy(base: BaseFields): T -} - -trait UpdateRepr[T, R <: HList] { - def apply(t: T, r: R): T -} - -object UpdateRepr { - import ops.record._ - - implicit def mergeUpdateRepr[T <: HList, R <: HList]( - implicit merger: Merger.Aux[T, R, T] - ): UpdateRepr[T, R] = merger(_, _) - - implicit def cnilUpdateRepr[R <: HList]: UpdateRepr[CNil, R] = - (t, _) => t - - implicit def cconsUpdateRepr[H, T <: Coproduct, R <: HList]( - implicit - uh: => UpdateRepr[H, R], - ut: => UpdateRepr[T, R] - ): UpdateRepr[H :+: T, R] = { - case (Inl(h), r) => Inl(uh(h, r)) - case (Inr(t), r) => Inr(ut(t, r)) - } - - implicit def genProdUpdateRepr[T, R <: HList, Repr <: HList]( - implicit - prod: HasProductGeneric[T], - gen: LabelledGeneric.Aux[T, Repr], - update: => UpdateRepr[Repr, R] - ): UpdateRepr[T, R] = - (t, r) => gen.from(update(gen.to(t), r)) - - implicit def genCoprodUpdateRepr[T, R <: HList, Repr <: Coproduct]( - implicit - coprod: HasCoproductGeneric[T], - gen: Generic.Aux[T, Repr], - update: => UpdateRepr[Repr, R] - ): UpdateRepr[T, R] = - (t, r) => gen.from(update(gen.to(t), r)) -} diff --git a/examples/src/main/scala/shapeless/examples/boolinduction.scala b/examples/src/main/scala/shapeless/examples/boolinduction.scala index 7aacc4fd7..d75c5a9df 100644 --- a/examples/src/main/scala/shapeless/examples/boolinduction.scala +++ b/examples/src/main/scala/shapeless/examples/boolinduction.scala @@ -17,19 +17,21 @@ package shapeless.examples object BooleanInduction extends App { - import shapeless._ - import syntax.singleton._ // Some preliminaries ... - val (wTrue, wFalse) = (true.witness, false.witness) - type True = wTrue.T - type False = wFalse.T + val (wTrue, wFalse) = (true, false) + type True = true + type False = false trait If[C <: Boolean, A, B] { type T ; def apply(a: A, b: B): T } object If { - implicit def ifTrue[A, B] = new If[True, A, B] { type T = A ; def apply(a: A, b: B) = a } - implicit def ifFalse[A, B] = new If[False, A, B] { type T = B ; def apply(a: A, b: B) = b } + implicit def ifTrue[A, B]: If[True, A, B] { + type T = A + } = new If[True, A, B] { type T = A ; def apply(a: A, b: B) = a } + implicit def ifFalse[A, B]: If[False, A, B] { + type T = B + } = new If[False, A, B] { type T = B ; def apply(a: A, b: B) = b } } // Scala translation of: @@ -38,16 +40,16 @@ object BooleanInduction extends App { // bool-induction P pt pf true = pt // bool-induction P pt pf false = pf - def boolInduction[P <: { type Case[_ <: Boolean] <: { type T }}, PT, PF] - (p: P)(t: PT)(f: PF)(x: Witness.Lt[Boolean]) - (implicit pt: p.Case[True] { type T = PT }, pf: p.Case[False] { type T = PF }, sel: If[x.T, PT, PF]): sel.T = sel(t, f) + def boolInduction[P <: { type Case[_ <: Boolean] <: { type T }}, PT, PF, B <: Boolean with Singleton] + (p: P)(t: PT)(f: PF)(x: B) + (implicit pt: p.Case[True] { type T = PT }, pf: p.Case[False] { type T = PF }, sel: If[B, PT, PF]): sel.T = sel(t, f) // In use ... object si { trait Case[B <: Boolean] { type T } - implicit val sit = new Case[True] { type T = String } - implicit val sif = new Case[False] { type T = Int } + implicit val sit: Case[True] { type T = String } = new Case[True] { type T = String } + implicit val sif: Case[False] { type T = Int } = new Case[False] { type T = Int } } val bt: String = boolInduction(si)("foo")(23)(true) diff --git a/examples/src/main/scala/shapeless/examples/cartesianproduct.scala b/examples/src/main/scala/shapeless/examples/cartesianproduct.scala index fd28512dd..b2c3951b0 100644 --- a/examples/src/main/scala/shapeless/examples/cartesianproduct.scala +++ b/examples/src/main/scala/shapeless/examples/cartesianproduct.scala @@ -41,14 +41,14 @@ object CartesianProductExample extends App { } object ApplyMapper { - implicit def hnil[HF, A] = new ApplyMapper[HF, A, HNil, HNil] { + implicit def hnil[HF, A]: ApplyMapper[HF, A, HNil, HNil] = new ApplyMapper[HF, A, HNil, HNil] { def apply(a: A, x: HNil) = HNil } implicit def hlist[HF, A, XH, XT <: HList, OutH, OutT <: HList](implicit applied: Case2.Aux[HF, A, XH, OutH], mapper: ApplyMapper[HF, A, XT, OutT] - ) = new ApplyMapper[HF, A, XH :: XT, OutH :: OutT] { + ): ApplyMapper[HF, A, XH :: XT, OutH :: OutT] = new ApplyMapper[HF, A, XH :: XT, OutH :: OutT] { def apply(a: A, x: XH :: XT) = applied(a, x.head) :: mapper(a, x.tail) } } @@ -62,7 +62,7 @@ object CartesianProductExample extends App { } object LiftA2 { - implicit def hnil[HF, Y <: HList] = new LiftA2[HF, HNil, Y, HNil] { + implicit def hnil[HF, Y <: HList]: LiftA2[HF, HNil, Y, HNil] = new LiftA2[HF, HNil, Y, HNil] { def apply(x: HNil, y: Y) = HNil } @@ -73,7 +73,7 @@ object CartesianProductExample extends App { mapper: ApplyMapper[HF, XH, Y, Out1], lift: LiftA2[HF, XT, Y, Out2], prepend : Prepend[Out1, Out2] - ) = new LiftA2[HF, XH :: XT, Y, prepend.Out] { + ): CartesianProductExample.LiftA2[HF, XH :: XT, Y, prepend.Out] = new LiftA2[HF, XH :: XT, Y, prepend.Out] { def apply(x: XH :: XT, y: Y) = prepend(mapper(x.head, y), lift(x.tail, y)) } } @@ -90,7 +90,7 @@ object CartesianProductExample extends App { * A polymorphic binary function that pairs its arguments. */ object tuple extends Poly { - implicit def whatever[A, B] = use((a : A, b : B) => (a, b)) + implicit def whatever[A, B]: ProductCase.Aux[A :: B :: HNil, (A, B)] = use((a : A, b : B) => (a, b)) } // Two example lists. diff --git a/examples/src/main/scala/shapeless/examples/derivation.scala b/examples/src/main/scala/shapeless/examples/derivation.scala index ec3f7a263..7872387bb 100644 --- a/examples/src/main/scala/shapeless/examples/derivation.scala +++ b/examples/src/main/scala/shapeless/examples/derivation.scala @@ -145,16 +145,16 @@ object TypeClassesDemoAux { implicit val deriveHNil: Show[HNil] = _ => "" implicit val deriveCNil: Show[CNil] = _ => "" - implicit def deriveHCons[K <: String, V, T <: HList]( - implicit key: Witness.Aux[K], sv: => Show[V], st: Show[T] + implicit def deriveHCons[K <: String with Singleton, V, T <: HList]( + implicit key: ValueOf[K], sv: => Show[V], st: Show[T] ): Show[FieldType[K, V] :: T] = { case kv :: t => val head = s"${key.value} = ${sv.show(kv)}" val tail = st.show(t) if (tail.isEmpty) head else s"$head, $tail" } - implicit def deriveCCons[K <: String, V, T <: Coproduct]( - implicit key: Witness.Aux[K], sv: => Show[V], st: Show[T] + implicit def deriveCCons[K <: String with Singleton, V, T <: Coproduct]( + implicit key: ValueOf[K], sv: => Show[V], st: Show[T] ): Show[FieldType[K, V] :+: T] = { case Inl(l) => s"${key.value}(${sv.show(l)})" case Inr(r) => st.show(r) diff --git a/examples/src/main/scala/shapeless/examples/enum.scala b/examples/src/main/scala/shapeless/examples/enum.scala index a7f39bfcb..46bef5bf4 100644 --- a/examples/src/main/scala/shapeless/examples/enum.scala +++ b/examples/src/main/scala/shapeless/examples/enum.scala @@ -97,8 +97,8 @@ object Values { implicit def cnilAux[A]: Aux[A, CNil] = new Aux[A, CNil] { def values = Nil } - implicit def cconsAux[T, L <: T, R <: Coproduct] - (implicit l: Witness.Aux[L], r: Aux[T, R]): Aux[T, L :+: R] = + implicit def cconsAux[T, L <: T with Singleton, R <: Coproduct] + (implicit l: ValueOf[L], r: Aux[T, R]): Aux[T, L :+: R] = new Aux[T, L :+: R] { def values = l.value :: r.values } } } diff --git a/examples/src/main/scala/shapeless/examples/factorial.scala b/examples/src/main/scala/shapeless/examples/factorial.scala index b48a4d5b4..6e3ef4c06 100644 --- a/examples/src/main/scala/shapeless/examples/factorial.scala +++ b/examples/src/main/scala/shapeless/examples/factorial.scala @@ -30,7 +30,7 @@ object FactorialExamples { trait Factorial[I <: Nat] { type Out <: Nat } object Factorial { - def factorial[N <: Nat](i : Nat)(implicit fact : Factorial.Aux[i.N, N], wn : Witness.Aux[N]): N = wn.value + def factorial[N <: Nat](i : Nat)(implicit fact : Factorial.Aux[i.N, N], wn : ValueOf[N]): N = wn.value type Aux[I <: Nat, Out0 <: Nat] = Factorial[I] { type Out = Out0 } diff --git a/examples/src/main/scala/shapeless/examples/fibonacci.scala b/examples/src/main/scala/shapeless/examples/fibonacci.scala index fa428e676..932b7851f 100644 --- a/examples/src/main/scala/shapeless/examples/fibonacci.scala +++ b/examples/src/main/scala/shapeless/examples/fibonacci.scala @@ -35,15 +35,15 @@ object FibonacciExamples { object Fibonacci { def apply(i: Nat, j: Nat) = new Fibonacci[i.N, j.N] - implicit val fib0 = Fibonacci(0, 0) - implicit val fib1 = Fibonacci(1, 1) + implicit val fib0: Fibonacci[_0, _0] = Fibonacci(0, 0) + implicit val fib1: Fibonacci[_1, _1] = Fibonacci(1, 1) implicit def fibN[I <: Nat, L <: Nat, M <: Nat] - (implicit l : Fibonacci[I, L], m : Fibonacci[Succ[I], M], sum : Sum[L, M]) = + (implicit l : Fibonacci[I, L], m : Fibonacci[Succ[I], M], sum : Sum[L, M]): Fibonacci[Succ[Succ[I]], sum.Out] = new Fibonacci[Succ[Succ[I]], sum.Out] } - def fibonacci[N <: Nat](i : Nat)(implicit fib : Fibonacci[i.N, N], wn: Witness.Aux[N]): N = wn.value + def fibonacci[N <: Nat](i : Nat)(implicit fib : Fibonacci[i.N, N], wn: ValueOf[N]): N = wn.value val f0 = fibonacci(0) typed[_0](f0) @@ -76,12 +76,12 @@ object FibonacciExamples { } object Fibs { - implicit def fibs0 = new Fibs[_0, HNil] { + implicit def fibs0: Fibs[_0, HNil] = new Fibs[_0, HNil] { def apply() = HNil } implicit def fibsN[N <: Nat, H <: Nat, T <: HList] - (implicit fib : Fibonacci[N, H], h : Witness.Aux[H], fibs : Fibs[N, T]) = + (implicit fib : Fibonacci[N, H], h : ValueOf[H], fibs : Fibs[N, T]): Fibs[Succ[N], H :: T] = new Fibs[Succ[N], H :: T] { def apply() = h.value :: fibs() } diff --git a/examples/src/main/scala/shapeless/examples/fizzbuzz.scala b/examples/src/main/scala/shapeless/examples/fizzbuzz.scala index 863dd1223..264b3870f 100644 --- a/examples/src/main/scala/shapeless/examples/fizzbuzz.scala +++ b/examples/src/main/scala/shapeless/examples/fizzbuzz.scala @@ -114,10 +114,10 @@ object FizzBuzzExample { /** Converts subtypes of FizzBuzz into string representations */ object FizzBuzzToString extends Poly1 { - implicit val fizz = at[Fizz.type](_ => "fizz") - implicit val buzz = at[Buzz.type](_ => "buzz") - implicit val fizzAndBuzz = at[FizzAndBuzz.type](_ => "fizzbuzz") - implicit def other[N <: Nat](implicit t: ToInt[N]) = at[Other[N]](n => t().toString) + implicit val fizz: Case.Aux[Fizz.type, String] = at[Fizz.type](_ => "fizz") + implicit val buzz: Case.Aux[Buzz.type, String] = at[Buzz.type](_ => "buzz") + implicit val fizzAndBuzz: Case.Aux[FizzAndBuzz.type, String] = at[FizzAndBuzz.type](_ => "fizzbuzz") + implicit def other[N <: Nat](implicit t: ToInt[N]): Case.Aux[Other[N], String] = at[Other[N]](n => t().toString) } /** diff --git a/examples/src/main/scala/shapeless/examples/flatten.scala b/examples/src/main/scala/shapeless/examples/flatten.scala index a2e1c1325..ced97b9a5 100644 --- a/examples/src/main/scala/shapeless/examples/flatten.scala +++ b/examples/src/main/scala/shapeless/examples/flatten.scala @@ -28,10 +28,10 @@ object FlattenExample { import test._ trait LowPriorityFlatten extends Poly1 { - implicit def default[T] = at[T](Tuple1(_)) + implicit def default[T]: Case.Aux[T, Tuple1[T]] = at[T](Tuple1(_)) } object flatten extends LowPriorityFlatten { - implicit def caseTuple[P <: Product, O](implicit lfm: => FlatMapper.Aux[P, flatten.type, O]) = + implicit def caseTuple[P <: Product, O](implicit lfm: => FlatMapper.Aux[P, flatten.type, O]): Case.Aux[P, O] = at[P](lfm(_)) } @@ -41,8 +41,8 @@ object FlattenExample { typed[List[Int]](l1) object toDouble extends Poly1 { - implicit def caseInt = at[Int](_.toDouble) - implicit def caseDouble = at[Double](identity) + implicit def caseInt: Case.Aux[Int, Double] = at[Int](_.toDouble) + implicit def caseDouble: Case.Aux[Double, Double] = at[Double](identity) } val t2 = (1, ((2, 3.0), 4)) diff --git a/examples/src/main/scala/shapeless/examples/fold.scala b/examples/src/main/scala/shapeless/examples/fold.scala index c034f2c83..82cafce1c 100644 --- a/examples/src/main/scala/shapeless/examples/fold.scala +++ b/examples/src/main/scala/shapeless/examples/fold.scala @@ -28,8 +28,8 @@ object FoldExamples extends App { // (c : Char, s : String) => s.indexOf(c) // (i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") object combine extends Poly { - implicit def caseCharString = use((c : Char, s : String) => s.indexOf(c)) - implicit def caseIntBoolean = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") + implicit def caseCharString: ProductCase.Aux[Char :: String :: HNil, Int] = use((c : Char, s : String) => s.indexOf(c)) + implicit def caseIntBoolean: ProductCase.Aux[Int :: Boolean :: HNil, String] = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") } // Computation is: diff --git a/examples/src/main/scala/shapeless/examples/gcd.scala b/examples/src/main/scala/shapeless/examples/gcd.scala index b7e1eb9e9..f0d2e110e 100644 --- a/examples/src/main/scala/shapeless/examples/gcd.scala +++ b/examples/src/main/scala/shapeless/examples/gcd.scala @@ -30,7 +30,7 @@ object GCDExamples { trait GCD[X <: Nat, Y <: Nat] { type Out <: Nat } object GCD { - def gcd[N <: Nat](x : Nat, y : Nat)(implicit gcd : Aux[x.N, y.N, N], wn : Witness.Aux[N]): N = wn.value + def gcd[N <: Nat](x : Nat, y : Nat)(implicit gcd : Aux[x.N, y.N, N], wn : ValueOf[N]): N = wn.value type Aux[X <: Nat, Y <: Nat, Z <: Nat] = GCD[X, Y] { type Out = Z } diff --git a/examples/src/main/scala/shapeless/examples/labelledgeneric.scala b/examples/src/main/scala/shapeless/examples/labelledgeneric.scala index d49b5f65e..30af07fad 100644 --- a/examples/src/main/scala/shapeless/examples/labelledgeneric.scala +++ b/examples/src/main/scala/shapeless/examples/labelledgeneric.scala @@ -77,7 +77,7 @@ trait Field { } object Field { - def apply[K0, V0](sample: FieldType[K0, V0]) = new Field { type K = K0; type V = V0 } + def apply[K0 <: Singleton, V0](sample: FieldType[K0, V0]) = new Field { type K = K0; type V = V0 } } object OldWineNewBottles extends App { @@ -93,7 +93,8 @@ object OldWineNewBottles extends App { val toGen = LabelledGeneric[To] // Define the type of the i field by example - val iField = Field("i" ->> 0) + val fieldType = "i" ->> 0 + val iField = Field(fieldType) val align = Align[iField.F :: fromGen.Repr, toGen.Repr] diff --git a/examples/src/main/scala/shapeless/examples/linearalgebra.scala b/examples/src/main/scala/shapeless/examples/linearalgebra.scala index 68d92d91e..b78739395 100644 --- a/examples/src/main/scala/shapeless/examples/linearalgebra.scala +++ b/examples/src/main/scala/shapeless/examples/linearalgebra.scala @@ -38,7 +38,7 @@ object LinearAlgebraExamples extends App { object VectorOps { type HomPair[T] = (T, T) object sum extends Poly1 { - implicit def caseDouble = at[Double :: Double :: HNil]{ case a :: b :: HNil => a+b } + implicit def caseDouble: Case.Aux[Double :: Double :: HNil, Double] = at[Double :: Double :: HNil]{ case a :: b :: HNil => a+b } } implicit def pointOps1(p : Tuple1[Double]) : VectorOps[_1, Tuple1[Double]] = new VectorOps[_1, Tuple1[Double]](p) { diff --git a/examples/src/main/scala/shapeless/examples/newtype.scala b/examples/src/main/scala/shapeless/examples/newtype.scala index bf3ccfe66..2703fea0d 100644 --- a/examples/src/main/scala/shapeless/examples/newtype.scala +++ b/examples/src/main/scala/shapeless/examples/newtype.scala @@ -31,7 +31,7 @@ object NewtypeExamples extends App { case class MyStringOps(s : String) { def mySize = s.size } - implicit val mkOps = MyStringOps + implicit val mkOps: MyStringOps.type = MyStringOps val ms = MyString("foo") diff --git a/examples/src/main/scala/shapeless/examples/pack.scala b/examples/src/main/scala/shapeless/examples/pack.scala index 654c2f387..c6b6ad36d 100644 --- a/examples/src/main/scala/shapeless/examples/pack.scala +++ b/examples/src/main/scala/shapeless/examples/pack.scala @@ -94,9 +94,9 @@ object PackExamples extends App { val b = new B {} val c = new C {} - implicit val sa = new Show[A] { def show = "A" } - implicit val sb = new Show[B] { def show = "B" } - implicit val sc = new Show[C] { def show = "C" } + implicit val sa: Show[A] = new Show[A] { def show = "A" } + implicit val sb: Show[B] = new Show[B] { def show = "B" } + implicit val sc: Show[C] = new Show[C] { def show = "C" } def use3[T, U, V](t : T, u : U, v : V)(implicit pack : Pack[Show, T :: U :: V :: HNil]) = { // Instances automatically unpacked here diff --git a/examples/src/main/scala/shapeless/examples/parsing.scala b/examples/src/main/scala/shapeless/examples/parsing.scala index 221632c16..7ce5b0a2f 100644 --- a/examples/src/main/scala/shapeless/examples/parsing.scala +++ b/examples/src/main/scala/shapeless/examples/parsing.scala @@ -44,21 +44,21 @@ object CombinatorTesting extends App { /** * Type class instance for `String`. */ - implicit def flattenString = new Flatten[String] { + implicit def flattenString: Flatten[String] = new Flatten[String] { def apply(m : String) = List(m) } /** * Flatten instance for `A ~ B`. Requires Flatten instances for `A` and `B`. */ - implicit def flattenPattern[A, B](implicit flattenA : Flatten[A], flattenB : Flatten[B]) = new Flatten[A ~ B] { + implicit def flattenPattern[A, B](implicit flattenA : Flatten[A], flattenB : Flatten[B]): Flatten[A ~ B] = new Flatten[A ~ B] { def apply(m : A ~ B) = m match { case a ~ b => flattenA(a) ::: flattenB(b) } } /** * Flatten instance for ParseResult[T]. Requires a Flatten instance for T. */ - implicit def flattenParseResult[T](implicit flattenP : Flatten[T]) = new Flatten[ParseResult[T]] { + implicit def flattenParseResult[T](implicit flattenP : Flatten[T]): Flatten[ParseResult[T]] = new Flatten[ParseResult[T]] { def apply(p : ParseResult[T]) = (p map flattenP) getOrElse Nil } diff --git a/examples/src/main/scala/shapeless/examples/recordsubtyping.scala b/examples/src/main/scala/shapeless/examples/recordsubtyping.scala index da1b3bd4f..c998fc3df 100644 --- a/examples/src/main/scala/shapeless/examples/recordsubtyping.scala +++ b/examples/src/main/scala/shapeless/examples/recordsubtyping.scala @@ -3,6 +3,7 @@ package shapeless.examples import shapeless._ import shapeless.poly._ import record._ +import labelled.->> import shapeless.ops.record.DeepMerger import shapeless.ops.record.Extractor import shapeless.ops.record.MapValues @@ -26,19 +27,19 @@ object recordsubtyping extends App{ val employee2 = employee1.updated("company", "Bar Inc.") val employee3 = employee1.updated("city", new PopulatedCity("Chernobyl", 1) ) - type PersonId = Record.`"firstName" -> String, "lastName" -> String`.T - type Person = Record.`"id" -> PersonId, "city" -> City`.T + type PersonId = ("firstName" ->> String) :: ("lastName" ->> String) :: HNil + type Person = ("id" ->> PersonId) :: ("city" ->> City) :: HNil val somePerson: Person = Record(id = Record(firstName = "Jane", lastName = "Doe"), city = new City("San Francisco")) trait default extends Poly1 { - implicit def id[T] = at[T](identity) + implicit def id[T]: Case.Aux[T, T] = at[T](identity) } object toUpper extends default { - implicit def toUpStr = at[String](_.toUpperCase) - implicit def toUpCity = at[City](c => new City(c.name.toUpperCase)) - implicit def toUpHl[L <: HList](implicit mv: MapValues[this.type, L]) = at[L](mv(_)) + implicit def toUpStr: Case.Aux[String, String] = at[String](_.toUpperCase) + implicit def toUpCity: Case.Aux[City, City] = at[City](c => new City(c.name.toUpperCase)) + implicit def toUpHl[L <: HList](implicit mv: MapValues[this.type, L]): Case.Aux[L, mv.Out] = at[L](mv(_)) } //isSamePerson diff --git a/examples/src/main/scala/shapeless/examples/recursionschemes.scala b/examples/src/main/scala/shapeless/examples/recursionschemes.scala index 1bc55f851..91d3e2c7b 100644 --- a/examples/src/main/scala/shapeless/examples/recursionschemes.scala +++ b/examples/src/main/scala/shapeless/examples/recursionschemes.scala @@ -74,7 +74,7 @@ package recursionschemes { for (a <- oa; f <- of) yield f(a) } - implicit def constApp[T](implicit T: Monoid[T]) = + implicit def constApp[T](implicit T: Monoid[T]): Applicative[({ type F[x] = ConstF[T, x] })#F] = new Applicative[({ type F[x] = ConstF[T, x] })#F] { def pure[A](a: A): ConstF[T, A] = ConstF(T.empty) def app[A, B](ca: ConstF[T, A])(cf: ConstF[T, A => B]): ConstF[T, B] = diff --git a/examples/src/main/scala/shapeless/examples/sexp.scala b/examples/src/main/scala/shapeless/examples/sexp.scala index cbf98db17..0fe5e54d5 100644 --- a/examples/src/main/scala/shapeless/examples/sexp.scala +++ b/examples/src/main/scala/shapeless/examples/sexp.scala @@ -292,8 +292,8 @@ object SexpConvert { def ser(n: HNil) = SexpNil } - implicit def deriveHCons[K <: String, V, T <: HList]( - implicit key: Witness.Aux[K], scv: => SexpConvert[V], sct: SexpConvert[T] + implicit def deriveHCons[K <: String with Singleton, V, T <: HList]( + implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] ): SexpConvert[FieldType[K, V] :: T] = new SexpConvert[FieldType[K, V] :: T] { def deser(s: Sexp): Option[FieldType[K, V] :: T] = s match { case SexpProp((label, car), cdr) if label == key.value => @@ -321,8 +321,8 @@ object SexpConvert { def ser(t: CNil) = SexpNil } - implicit def deriveCCons[K <: String, V, T <: Coproduct]( - implicit key: Witness.Aux[K], scv: => SexpConvert[V], sct: SexpConvert[T] + implicit def deriveCCons[K <: String with Singleton, V, T <: Coproduct]( + implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] ): SexpConvert[FieldType[K, V] :+: T] = new SexpConvert[FieldType[K, V] :+: T] { def deser(s: Sexp): Option[FieldType[K, V] :+: T] = s match { case SexpCons(SexpAtom(impl), cdr) if impl == key.value => diff --git a/examples/src/main/scala/shapeless/examples/shows.scala b/examples/src/main/scala/shapeless/examples/shows.scala index 23763f297..41ffd287b 100644 --- a/examples/src/main/scala/shapeless/examples/shows.scala +++ b/examples/src/main/scala/shapeless/examples/shows.scala @@ -27,7 +27,7 @@ object ShowExamples extends App { case class BarRec(i: Int, rec: Super) extends Super object Super { - implicit val instance = Show[Super] + implicit val instance: Show[Super] = Show.deriveInstance } sealed trait MutualA @@ -39,11 +39,11 @@ object ShowExamples extends App { case class MutualB2(b: MutualA) extends MutualB object MutualA { - implicit val aInstance = Show[MutualA] + implicit val aInstance: Show[MutualA] = Show.deriveInstance } object MutualB { - implicit val bInstance = Show[MutualB] + implicit val bInstance: Show[MutualB] = Show.deriveInstance } val bar: Super = Bar(0) diff --git a/examples/src/main/scala/shapeless/examples/sorting.scala b/examples/src/main/scala/shapeless/examples/sorting.scala index 12a214686..a4aef002f 100644 --- a/examples/src/main/scala/shapeless/examples/sorting.scala +++ b/examples/src/main/scala/shapeless/examples/sorting.scala @@ -33,10 +33,10 @@ object Sorting { * Witness that an HList of Nats is in non-decreasing order at both type and value level. */ trait NonDecreasing[L <: HList] - implicit def hnilNonDecreasing = new NonDecreasing[HNil] {} - implicit def hlistNonDecreasing1[H] = new NonDecreasing[H :: HNil] {} + implicit def hnilNonDecreasing: NonDecreasing[HNil] = new NonDecreasing[HNil] {} + implicit def hlistNonDecreasing1[H]: NonDecreasing[H :: HNil] = new NonDecreasing[H :: HNil] {} implicit def hlistNonDecreasing2[H1 <: Nat, H2 <: Nat, T <: HList] - (implicit ltEq : H1 <= H2, ndt : NonDecreasing[H2 :: T]) = new NonDecreasing[H1 :: H2 :: T] {} + (implicit ltEq : H1 <= H2, ndt : NonDecreasing[H2 :: T]): NonDecreasing[H1 :: H2 :: T] = new NonDecreasing[H1 :: H2 :: T] {} def acceptNonDecreasing[L <: HList](l : L)(implicit ni : NonDecreasing[L]) = l @@ -57,14 +57,14 @@ object Sorting { } trait LowPrioritySelectLeast { - implicit def hlistSelectLeast1[H <: Nat, T <: HList] = new SelectLeast[H :: T, H, T] { + implicit def hlistSelectLeast1[H <: Nat, T <: HList]: SelectLeast[H :: T, H, T] = new SelectLeast[H :: T, H, T] { def apply(l : H :: T) : (H, T) = (l.head, l.tail) } } object SelectLeast extends LowPrioritySelectLeast { implicit def hlistSelectLeast3[H <: Nat, T <: HList, TM <: Nat, TRem <: HList] - (implicit tsl : SelectLeast[T, TM, TRem], ev : TM < H) = new SelectLeast[H :: T, TM, H :: TRem] { + (implicit tsl : SelectLeast[T, TM, TRem], ev : TM < H): SelectLeast[H :: T, TM, H :: TRem] = new SelectLeast[H :: T, TM, H :: TRem] { def apply(l : H :: T) : (TM, H :: TRem) = { val (tm, rem) = tsl(l.tail) (tm, l.head :: rem) @@ -90,14 +90,14 @@ object Sorting { } trait LowPrioritySelectionSort { - implicit def hlistSelectionSort1[S <: HList] = new SelectionSort[S, S] { + implicit def hlistSelectionSort1[S <: HList]: SelectionSort[S, S] = new SelectionSort[S, S] { def apply(l : S) : S = l } } object SelectionSort extends LowPrioritySelectionSort { implicit def hlistSelectionSort2[L <: HList, M <: Nat, Rem <: HList, ST <: HList] - (implicit sl : SelectLeast[L, M, Rem], sr : SelectionSort[Rem, ST]) = new SelectionSort[L, M :: ST] { + (implicit sl : SelectLeast[L, M, Rem], sr : SelectionSort[Rem, ST]): SelectionSort[L, M :: ST] = new SelectionSort[L, M :: ST] { def apply(l : L) = { val (m, rem) = sl(l) m :: sr(rem) diff --git a/examples/src/main/scala/shapeless/examples/staging.scala b/examples/src/main/scala/shapeless/examples/staging.scala index 7b4470fe6..9c3165856 100644 --- a/examples/src/main/scala/shapeless/examples/staging.scala +++ b/examples/src/main/scala/shapeless/examples/staging.scala @@ -25,11 +25,11 @@ object StagedTypeClassExample extends App { } object TupleConsumer { - implicit val intString = new TupleConsumer[Int, String] { + implicit val intString: TupleConsumer[Int, String] = new TupleConsumer[Int, String] { def apply(t: (Int, String)) = s"${t._1}${t._2}" } - implicit val booleanDouble = new TupleConsumer[Boolean, Double] { + implicit val booleanDouble: TupleConsumer[Boolean, Double] = new TupleConsumer[Boolean, Double] { def apply(t: (Boolean, Double)) = (if(t._1) "+" else "-")+t._2 } } diff --git a/examples/src/main/scala/shapeless/examples/unfold.scala b/examples/src/main/scala/shapeless/examples/unfold.scala index 6475e38c9..2694c69d5 100644 --- a/examples/src/main/scala/shapeless/examples/unfold.scala +++ b/examples/src/main/scala/shapeless/examples/unfold.scala @@ -73,10 +73,10 @@ object UnfoldExamples extends App { import Unfold.unfold object unfoldMisc extends Poly1 { - implicit def case0 = at[_0](_ => (23, _1)) - implicit def case1 = at[_1](_ => ("foo", _2)) - implicit def case2 = at[_2](_ => (true, _3)) - implicit def case3 = at[_3](_ => (1.0, _4)) + implicit def case0: Case.Aux[_0, (Int, _1)] = at[_0](_ => (23, _1)) + implicit def case1: Case.Aux[_1, (String, _2)] = at[_1](_ => ("foo", _2)) + implicit def case2: Case.Aux[_2, (Boolean, _3)] = at[_2](_ => (true, _3)) + implicit def case3: Case.Aux[_3, (Double, _4)] = at[_3](_ => (1.0, _4)) } val l1 = unfold(Nat(3))(unfoldMisc)(Nat(0)) @@ -84,19 +84,19 @@ object UnfoldExamples extends App { println(l1) object unfoldFibs extends Poly1 { - implicit def case0 = at[_0](_ => (_0, _1)) - implicit def case1 = at[_1](_ => (_1, _2)) + implicit def case0: Case.Aux[_0, (_0, _1)] = at[_0](_ => (_0, _1)) + implicit def case1: Case.Aux[_1, (_1, _2)] = at[_1](_ => (_1, _2)) implicit def caseN[N <: Nat, FN <: Nat, FSN <: Nat, FSSN <: Nat] (implicit fn : Case.Aux[N, (FN, Succ[N])], fsn : Case.Aux[Succ[N], (FSN, Succ[Succ[N]])], sum : Sum.Aux[FN, FSN, FSSN], - fssn : Witness.Aux[FSSN]) = + fssn : ValueOf[FSSN]): Case.Aux[Succ[Succ[N]], (FSSN, Succ[Succ[Succ[N]]])] = at[Succ[Succ[N]]](_ => ((fssn.value: FSSN), Succ[Succ[Succ[N]]]())) } object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toInt : ToInt[N]) = at[N](_ => toInt()) + implicit def default[N <: Nat](implicit toInt : ToInt[N]): Case.Aux[N, Int] = at[N](_ => toInt()) } val l2 = unfold(_6)(unfoldFibs)(Nat(0)) diff --git a/examples/src/main/scala/shapeless/examples/unwrapped.scala b/examples/src/main/scala/shapeless/examples/unwrapped.scala index 367526d3c..c00bb69a4 100644 --- a/examples/src/main/scala/shapeless/examples/unwrapped.scala +++ b/examples/src/main/scala/shapeless/examples/unwrapped.scala @@ -53,8 +53,8 @@ object UnwrappedExamples { implicit val encodeHNil: Encode[HNil] = instance(_ => Map.empty) - implicit def encodeHCons[K <: String, V, Rest <: HList]( - implicit key: Witness.Aux[K], encodeV: => EncodeValue[V], encodeRest: Encode[Rest] + implicit def encodeHCons[K <: String with Singleton, V, Rest <: HList]( + implicit key: ValueOf[K], encodeV: => EncodeValue[V], encodeRest: Encode[Rest] ): Encode[FieldType[K, V] :: Rest] = instance { case h :: t => encodeRest.fields(t) + (key.value -> encodeV.toJsonFragment(h)) } @@ -107,9 +107,9 @@ object UnwrappedExamples { implicit val encodeHNil: Encode2[HNil] = instance(_ => Map.empty) - implicit def encodeHCons[K <: String, V, U, Rest <: HList]( + implicit def encodeHCons[K <: String with Singleton, V, U, Rest <: HList]( implicit - key: Witness.Aux[K], + key: ValueOf[K], uw: Unwrapped.Aux[V, U], encodeV: => EncodeValue[U], encodeRest: Encode2[Rest] diff --git a/examples/src/main/scala/shapeless/examples/zipapply.scala b/examples/src/main/scala/shapeless/examples/zipapply.scala index 3031c8489..c7a634e14 100644 --- a/examples/src/main/scala/shapeless/examples/zipapply.scala +++ b/examples/src/main/scala/shapeless/examples/zipapply.scala @@ -23,7 +23,7 @@ import shapeless.ops.hlist._ // Spoiler alert - don't look! object compose extends Poly1 { - implicit def cases[A, B, C] = at[(A => B, B => C)] { + implicit def cases[A, B, C]: Case.Aux[(A => B, B => C), A => C] = at[(A => B, B => C)] { case (f1, f2) => f1 andThen f2 } } From b8d5f0058147708ff61bfcc8313f795d3ace5842 Mon Sep 17 00:00:00 2001 From: Katrix Date: Fri, 6 Aug 2021 02:35:36 +0200 Subject: [PATCH 29/32] Fixed more tests --- build.sbt | 4 + .../scala-2/shapeless/serialization.scala | 15 + .../test/scala/shapeless/serialization.scala | 8 - .../{scala/shapeless => scala-2}/refute.scala | 12 +- core/src/main/scala-2/shapeless/generic.scala | 6 +- .../main/scala-3/shapeless/annotation.scala | 86 ++- core/src/main/scala-3/shapeless/default.scala | 78 +-- core/src/main/scala-3/shapeless/generic.scala | 25 +- .../src/main/scala-3/shapeless/generic1.scala | 263 +++++---- core/src/main/scala-3/shapeless/nat.scala | 8 +- .../shapeless/ops/record/records.scala | 10 +- core/src/main/scala-3/shapeless/refute.scala | 18 + .../scala-3/shapeless/test/illTyped.scala | 58 +- .../main/scala-3/shapeless/test/types.scala | 11 +- .../scala-3/shapeless/typeoperators.scala | 2 +- core/src/main/scala/shapeless/Testing3.scala | 83 +++ .../test/scala-2/shapeless/annotations.scala | 15 + .../test/scala-2/shapeless/conversions.scala | 26 + core/src/test/scala-2/shapeless/generic.scala | 527 ++++++++++++++++++ .../shapeless/generic1.scala | 10 +- core/src/test/scala-2/shapeless/hlist.scala | 18 + .../shapeless/implicits.scala | 32 +- .../scala-2/shapeless/labelledgeneric.scala | 104 ++++ core/src/test/scala-2/shapeless/lenses.scala | 39 ++ core/src/test/scala-3/shapeless/generic.scala | 6 + core/src/test/scala-3/shapeless/hlist.scala | 13 + .../src/test/scala/shapeless/annotation.scala | 19 +- .../test/scala/shapeless/constraints.scala | 27 +- .../test/scala/shapeless/conversions.scala | 17 +- core/src/test/scala/shapeless/default.scala | 30 +- core/src/test/scala/shapeless/generic.scala | 517 +---------------- core/src/test/scala/shapeless/hlist.scala | 24 +- .../scala/shapeless/labelledgeneric.scala | 90 +-- core/src/test/scala/shapeless/lenses.scala | 30 - .../src/test/scala/shapeless/singletons.scala | 14 +- .../examples => scala-2/shapeless}/enum.scala | 8 +- 36 files changed, 1342 insertions(+), 911 deletions(-) create mode 100644 core/jvm/src/test/scala-2/shapeless/serialization.scala rename core/src/main/{scala/shapeless => scala-2}/refute.scala (81%) create mode 100644 core/src/main/scala-3/shapeless/refute.scala create mode 100644 core/src/main/scala/shapeless/Testing3.scala create mode 100644 core/src/test/scala-2/shapeless/annotations.scala create mode 100644 core/src/test/scala-2/shapeless/conversions.scala create mode 100644 core/src/test/scala-2/shapeless/generic.scala rename core/src/test/{scala => scala-2}/shapeless/generic1.scala (97%) create mode 100644 core/src/test/scala-2/shapeless/hlist.scala rename core/src/test/{scala => scala-2}/shapeless/implicits.scala (90%) create mode 100644 core/src/test/scala-2/shapeless/labelledgeneric.scala create mode 100644 core/src/test/scala-2/shapeless/lenses.scala create mode 100644 core/src/test/scala-3/shapeless/generic.scala create mode 100644 core/src/test/scala-3/shapeless/hlist.scala rename examples/src/main/{scala/shapeless/examples => scala-2/shapeless}/enum.scala (92%) diff --git a/build.sbt b/build.sbt index 163b5874f..bef17d08e 100644 --- a/build.sbt +++ b/build.sbt @@ -95,6 +95,10 @@ lazy val commonSettings = Seq( case Some((3, _)) => scalacOptions3 case _ => Nil }), + Test / compile / scalacOptions ++= (CrossVersion.partialVersion(scalaVersion.value) match { + case Some((3, _)) => Seq("-Yretain-trees") + case _ => Nil + }), libraryDependencies ++= (CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, _)) => scalaMacroDependencies.value case _ => Nil diff --git a/core/jvm/src/test/scala-2/shapeless/serialization.scala b/core/jvm/src/test/scala-2/shapeless/serialization.scala new file mode 100644 index 000000000..c90cbafc7 --- /dev/null +++ b/core/jvm/src/test/scala-2/shapeless/serialization.scala @@ -0,0 +1,15 @@ +package shapeless + +import org.junit.Test + +class SerializationTestsScala2 { + import SerializationTestDefns._ + + @Test + def testFunctor: Unit = { + assertSerializableBeforeAfter(Functor[Some])(_.map(Some(2))(_.toString)) + assertSerializableBeforeAfter(Functor[Option])(_.map(Option(2))(_.toString)) + assertSerializableBeforeAfter(Functor[Tree])(_.map(Leaf(2))(_.toString)) + assertSerializableBeforeAfter(Functor[List])(_.map(List(2))(_.toString)) + } +} diff --git a/core/jvm/src/test/scala/shapeless/serialization.scala b/core/jvm/src/test/scala/shapeless/serialization.scala index 1a81cf64e..9284f6c3a 100644 --- a/core/jvm/src/test/scala/shapeless/serialization.scala +++ b/core/jvm/src/test/scala/shapeless/serialization.scala @@ -1145,14 +1145,6 @@ class SerializationTests { assertSerializableBeforeAfter(implicitly[Everywhere[poly.identity.type, Wibble]])(_(Wibble(2, "a"))) } - @Test - def testFunctor: Unit = { - assertSerializableBeforeAfter(Functor[Some])(_.map(Some(2))(_.toString)) - assertSerializableBeforeAfter(Functor[Option])(_.map(Option(2))(_.toString)) - assertSerializableBeforeAfter(Functor[Tree])(_.map(Leaf(2))(_.toString)) - assertSerializableBeforeAfter(Functor[List])(_.map(List(2))(_.toString)) - } - @Test def testShow: Unit = { // I had to disable the first two during https://github.com/milessabin/shapeless/pull/435, with scala 2.12.0-M2. diff --git a/core/src/main/scala/shapeless/refute.scala b/core/src/main/scala-2/refute.scala similarity index 81% rename from core/src/main/scala/shapeless/refute.scala rename to core/src/main/scala-2/refute.scala index f7ca16475..02dc5f984 100644 --- a/core/src/main/scala/shapeless/refute.scala +++ b/core/src/main/scala-2/refute.scala @@ -1,9 +1,9 @@ package shapeless /** Evidence that no implicit instance of type `T` is available - * - * @author Zainab Ali - */ + * + * @author Zainab Ali + */ @annotation.implicitNotFound(msg = "Implicit instance for ${T} in scope.") trait Refute[T] @@ -17,8 +17,8 @@ object Refute { } /** This always declares an instance of `Refute` - * - * This instance will only be found when there is no evidence of `T` - * */ + * + * This instance will only be found when there is no evidence of `T` + * */ implicit def refute[T](implicit dummy: Impl[T]): Refute[T] = new Refute[T] {} } diff --git a/core/src/main/scala-2/shapeless/generic.scala b/core/src/main/scala-2/shapeless/generic.scala index e54fb98e3..6db61f143 100644 --- a/core/src/main/scala-2/shapeless/generic.scala +++ b/core/src/main/scala-2/shapeless/generic.scala @@ -182,20 +182,24 @@ trait CaseClassMacros extends ReprTypes with CaseClassMacrosVersionSpecifics { } val baseArgs = baseTpe.dealias.typeArgs + /* def isLess(sym1: Symbol, sym2: Symbol): Boolean = { val global = c.universe.asInstanceOf[scala.tools.nsc.Global] val gSym1 = sym1.asInstanceOf[global.Symbol] val gSym2 = sym2.asInstanceOf[global.Symbol] gSym1.isLess(gSym2) } + */ + /* def orderSyms(s1: Symbol, s2: Symbol): Boolean = { val fn1 = s1.fullName val fn2 = s2.fullName fn1 < fn2 || (fn1 == fn2 && isLess(s1, s2)) } + */ - val ctors = collectCtors(baseSym).sortWith(orderSyms).flatMap { sym => + val ctors = collectCtors(baseSym).flatMap { sym => import c.internal._ val owner = sym.owner diff --git a/core/src/main/scala-3/shapeless/annotation.scala b/core/src/main/scala-3/shapeless/annotation.scala index 58e4d3686..ff1aa75a1 100644 --- a/core/src/main/scala-3/shapeless/annotation.scala +++ b/core/src/main/scala-3/shapeless/annotation.scala @@ -53,16 +53,35 @@ object AnnotationMacros { } } - private def findAnnotation[A: Type](using quotes: Quotes)(symbol: quotes.reflect.Symbol): Option[Expr[A]] = { + private def annotationsFromType(using quotes: Quotes)(enclosing: quotes.reflect.TypeRepr, tpe: quotes.reflect.TypeRepr): List[quotes.reflect.Term] = { + import quotes.reflect.* + tpe match { + case AnnotatedType(rest, term) => + term :: annotationsFromType(enclosing, rest) + //case ClassInfo(_, _, parents) => parents.flatMap(fromType(enclosing, _)) + case ref @ TypeRef(_, _) if ref.typeSymbol.isAliasType => annotationsFromType(enclosing, enclosing.memberType(ref.typeSymbol)) + case TypeBounds(low, hi) if low == hi => annotationsFromType(enclosing, low) + case _ => + Nil + } + } + + private def findAnnotation[A: Type](using quotes: Quotes)(tpe: quotes.reflect.TypeRepr, symbol: quotes.reflect.Symbol, typeAnnotations: Boolean = false): Option[Expr[A]] = { import quotes.reflect.* val annotationType = TypeRepr.of[A] - symbol.annotations.find(_.tpe <:< annotationType).map(_.asExprOf[A]) + + val annotations = if (typeAnnotations) + annotationsFromType(tpe, tpe.memberType(symbol)) + else + symbol.annotations + + annotations.find(_.tpe <:< annotationType).map(_.asExprOf[A]) } private def singleAnnotationForTypeCommon[A: Type, T: Type](using quotes: Quotes): Option[Expr[A]] = { import quotes.reflect.* errorIfInvalidAnnotation[A] - findAnnotation[A](TypeRepr.of[T].typeSymbol) + findAnnotation[A](TypeRepr.of[T], TypeRepr.of[T].typeSymbol) } def singleAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[A, T]] = { @@ -109,18 +128,24 @@ object AnnotationMacros { } } - def allAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[Annotations[A, T]] = { + def allAnnotationsCommon[A: Type, T: Type, Out](typeAnnotations: Boolean)( + makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] + )(using quotes: Quotes): Expr[Out] = { import quotes.reflect.* errorIfInvalidAnnotation[A] - + val tpe = TypeRepr.of[T] val annotations = productOrSumSymbols[T].map { symbol => - findAnnotation[A](symbol) match { + findAnnotation[A](tpe, symbol, typeAnnotations) match { case Some(expr) =>'{Some($expr)} case None => '{None} } } - listExprToResult[HNil, Annotations[A, T]]('{HNil: HNil}, annotations.reverse) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + listExprToResult[HNil, Out]('{HNil: HNil}, annotations.reverse)(makeResult) + } + + def allAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[Annotations[A, T]] = { + allAnnotationsCommon[A, T, Annotations[A, T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => '{ new Annotations[A, T] { override type Out = Acc @@ -131,29 +156,50 @@ object AnnotationMacros { } def allTypeAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[TypeAnnotations[A, T]] = { - import quotes.reflect.* - errorIfInvalidAnnotation[A] - ??? + allAnnotationsCommon[A, T, TypeAnnotations[A, T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new TypeAnnotations[A, T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + } } - def allAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllAnnotations[T]] = { + def allAnnotationsForTypeCommon[T: Type, Out](typeAnnotations: Boolean)( + makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] + )(using quotes: Quotes): Expr[Out] = { import quotes.reflect.* - + val tpe = TypeRepr.of[T] val annotationLists = productOrSumSymbols[T].map { symbol => - listExprToHList(symbol.annotations.map(_.asExpr)) + val annotations = if(typeAnnotations) + annotationsFromType(tpe, tpe.memberType(symbol)) + else + symbol.annotations + listExprToHList(annotations.map(_.asExpr)) } - listExprToResult[HNil, AllAnnotations[T]]('{HNil: HNil}, annotationLists.reverse) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + listExprToResult[HNil, Out]('{HNil: HNil}, annotationLists.reverse)(makeResult) + } + + def allAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllAnnotations[T]] = { + allAnnotationsForTypeCommon[T, AllAnnotations[T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => '{ - new AllAnnotations[T] { - override type Out = Acc - override def apply(): Out = $acc - } + new AllAnnotations[T] { + override type Out = Acc + override def apply(): Out = $acc + } } } } def allTypeAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllTypeAnnotations[T]] = { - import quotes.reflect.* - ??? + allAnnotationsForTypeCommon[T, AllTypeAnnotations[T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new AllTypeAnnotations[T] { + override type Out = Acc + override def apply(): Out = $acc + } + } + } } } diff --git a/core/src/main/scala-3/shapeless/default.scala b/core/src/main/scala-3/shapeless/default.scala index 23a8a4c06..bed8c9ba3 100644 --- a/core/src/main/scala-3/shapeless/default.scala +++ b/core/src/main/scala-3/shapeless/default.scala @@ -15,48 +15,62 @@ object DefaultScalaCompat { tpe.classSymbol match { case Some(classSymbol) => - val constructorParams = classSymbol.primaryConstructor.paramSymss - if(constructorParams.sizeIs > 1) { - report.throwError(s"Found more than one parameter list for ${tpe.show}") + + if (classSymbol.moduleClass == classSymbol) { + '{ + new Default[T] { + override type Out = HNil + override def apply(): HNil = HNil + } + } + } + else if (classSymbol.flags.is(Flags.Abstract) || classSymbol.flags.is(Flags.Trait)) { + report.throwError(s"${tpe.show} is abstract") } + else { + val constructorParams = classSymbol.primaryConstructor.paramSymss + if(constructorParams.sizeIs > 1) { + report.throwError(s"Found more than one parameter list for ${tpe.show}") + } - val constructorParamsSize = constructorParams.head.size + val constructorParamsSize = constructorParams.head.size + if(constructorParamsSize == 0) { + report.throwError(s"${tpe.show} has an empty constructor") + } - val moduleClass = classSymbol.companionModule.moduleClass - val defaultMethods = (1 to constructorParamsSize).map { i => - moduleClass.declaredMethod(defaultConstructorMethodNames + i).headOption - } + val moduleClass = classSymbol.companionModule.moduleClass + val defaultMethods = (1 to constructorParamsSize).map { i => + moduleClass.declaredMethod(defaultConstructorMethodNames + i).headOption + } - val defaultExprs = defaultMethods.map { - case Some(method) => - val DefDef(_, _, _, optDefault) = method.tree - val default = optDefault.getOrElse( - report.throwError("Found empty tree for default. Make sure that the compiler option -Yretain-trees is enabled") - ) + val defaultExprs = defaultMethods.map { + case Some(method) => + val DefDef(_, _, tpeTree, optDefault) = method.tree + val default = optDefault.getOrElse( + report.throwError("Found empty tree for default. Make sure that the compiler option -Yretain-trees is enabled") + ) - default.asExpr match { - case '{$defaultExpr: t} => - defaultExpr.asTerm.tpe.widen.asType match { - case '[t2] => '{Some($defaultExpr.asInstanceOf[t2])} - } - } + tpeTree.tpe.asType match { + case '[t2] => '{Some(${default.asExpr}.asInstanceOf[t2])} + } - case None => '{None} - } + case None => '{None} + } - def result[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[Any]]): Expr[Default[T]] = - rest match { - case Nil => '{ - new Default[T] { - override type Out = Acc - override def apply(): Acc = $acc + def result[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[Any]]): Expr[Default[T]] = + rest match { + case Nil => '{ + new Default[T] { + override type Out = Acc + override def apply(): Acc = $acc + } } + case Seq('{$head: tpe}, tail*) => + result('{new ::($head, $acc)}, tail) } - case Seq('{$head: tpe}, tail*) => - result('{new ::($head, $acc)}, tail) - } - result('{HNil: HNil}, defaultExprs.reverse) + result('{HNil: HNil}, defaultExprs.reverse) + } case _ => report.throwError(s"Invalid type ${tpe.show}. Expected a class.") diff --git a/core/src/main/scala-3/shapeless/generic.scala b/core/src/main/scala-3/shapeless/generic.scala index 92a823454..297539c9b 100644 --- a/core/src/main/scala-3/shapeless/generic.scala +++ b/core/src/main/scala-3/shapeless/generic.scala @@ -18,16 +18,27 @@ package shapeless import scala.deriving._ -trait GenericScalaCompat { +trait GenericScalaCompat extends GenericScalaCompatLowPriority { - given Generic.Aux[Unit, Unit :: HNil] = new Generic[Unit] { - override type Repr = Unit :: HNil + given Generic.Aux[Unit, HNil] = new Generic[Unit] { + override type Repr = HNil - override def to(t: Unit): Repr = t :: HNil + override def to(t: Unit): Repr = HNil - override def from(r: Repr): Unit = r.head + override def from(r: Repr): Unit = () } + given[A <: AnyRef & Singleton](using v: ValueOf[A]): Generic.Aux[A, HNil] = new Generic[A] { + override type Repr = HNil + + override def to(t: A): Repr = HNil + + override def from(r: Repr): A = v.value + } +} + +trait GenericScalaCompatLowPriority { + transparent inline given materializeProduct[T <: Product]( using m: scala.deriving.Mirror.ProductOf[T] ): Generic.Aux[T, HList.TupleToHList[m.MirroredElemTypes]] = @@ -64,12 +75,12 @@ trait LabelledGenericScalaCompat { case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :+: MakeFieldsCoproduct[types, labels] } - given materializeProduct[T <: Product]( + transparent inline given materializeProduct[T <: Product]( using m: scala.deriving.Mirror.ProductOf[T] ): LabelledGeneric.Aux[T, MakeFieldsProduct[m.MirroredElemTypes, m.MirroredElemLabels]] = LabelledGeneric.unsafeInstance(Generic.materializeProduct) - given materializeSum[T]( + transparent inline given materializeSum[T]( using m: scala.deriving.Mirror.SumOf[T], ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, ): LabelledGeneric.Aux[T, MakeFieldsCoproduct[m.MirroredElemTypes, m.MirroredElemLabels]] = diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index 522da3b9e..834ec9022 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -66,7 +66,34 @@ trait Generic1ScalaCompat extends Generic10{ Generic1.fromSum[T, Apply11[FR, U]] } -trait Generic10ScalaCompat { +trait Generic10ScalaCompat extends Generic10ScalaCompatLowPriority { + + given[FR[_[_]]](using frr: => FR[Const[HNil]#λ]): Generic1.Aux[Const[Unit]#λ, FR, Const[HNil]#λ] = + new Generic1[Const[Unit]#λ, FR] { + override type R[Z] = HNil + + override def to[T](ft: Unit): HNil = HNil + + override def from[T](rt: HNil): Unit = () + + override def mkFrr: FR[Const[HNil]#λ] = frr + } + + given[A <: AnyRef & Singleton, FR[_[_]]]( + using v: ValueOf[A], + frr: => FR[Const[HNil]#λ] + ): Generic1.Aux[Const[A]#λ, FR, Const[HNil]#λ] = new Generic1[Const[A]#λ, FR] { + override type R[Z] = HNil + + override def to[T](ft: A): HNil = HNil + + override def from[T](rt: HNil): A = v.value + + override def mkFrr: FR[Const[HNil]#λ] = frr + } +} + +trait Generic10ScalaCompatLowPriority { given fromProduct[A[_] <: Product, FR[_[_]]]( using m: MirrorOf1Product[A], @@ -99,127 +126,117 @@ trait Generic10ScalaCompat { } } -type Head[T <: scala.Tuple] = T match { - case h *: _ => h -} - -type Tail[T <: scala.Tuple] <: scala.Tuple = T match { - case _ *: t => t -} - -type HeadElemTypes[ElemTypes[_] <: scala.Tuple] = [Z] =>> Head[ElemTypes[Z]] - -type TailElemTypesHCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> HList.TupleToHList[Tail[ElemTypes[Z]]] - trait IsHCons1ScalaCompat extends IsHCons10 { - given mkIsHCons10[L[_] <: Product, FH[_[_], _[_]], U[_], FT[_[_]]]( - using m: MirrorOf1Product[L], - fhh: => ApplyF[Apply10[FH, U], HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], - ): IsHCons1.Aux[L, Apply10[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = - IsHCons1.fromProduct[L, Apply10[FH, U], FT] - - given mkIsHCons11[L[_] <: Product, FH[_[_], _[_]], U[_], FT[_[_]]]( - using m: MirrorOf1Product[L], - fhh: => ApplyF[Apply11[FH, U], HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], - ): IsHCons1.Aux[L, Apply11[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = - IsHCons1.fromProduct[L, Apply11[FH, U], FT] - - given mkIsHCons12[L[_] <: Product, FH[_[_]], FT[_[_], _[_]], U[_]]( - using m: MirrorOf1Product[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[Apply10[FT, U], TailElemTypesHCons[m.MirroredElemTypes]], - ): IsHCons1.Aux[L, FH, Apply10[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = - IsHCons1.fromProduct[L, FH, Apply10[FT, U]] - - given mkIsHCons13[L[_] <: Product, FH[_[_]], FT[_[_], _[_]], U[_]]( - using m: MirrorOf1Product[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[Apply11[FT, U], TailElemTypesHCons[m.MirroredElemTypes]], - ): IsHCons1.Aux[L, FH, Apply11[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = - IsHCons1.fromProduct[L, FH, Apply11[FT, U]] + given mkIsHCons10[L[_], H[_], T[_] <: HList, FH[_[_], _[_]], U[_], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[Apply10[FH, U], H], + ftt: => ApplyF[FT, T], + ): IsHCons1.Aux[L, Apply10[FH, U], FT, H, T] = + IsHCons1.fromProduct[L, H, T, Apply10[FH, U], FT] + + given mkIsHCons11[L[_], H[_], T[_] <: HList, FH[_[_], _[_]], U[_], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[Apply11[FH, U], H], + ftt: => ApplyF[FT, T], + ): IsHCons1.Aux[L, Apply11[FH, U], FT, H, T] = + IsHCons1.fromProduct[L, H, T, Apply11[FH, U], FT] + + given mkIsHCons12[L[_], H[_], T[_] <: HList, FH[_[_]], FT[_[_], _[_]], U[_]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[FH, H], + ftt: => ApplyF[Apply10[FT, U], T], + ): IsHCons1.Aux[L, FH, Apply10[FT, U], H, T] = + IsHCons1.fromProduct[L, H, T, FH, Apply10[FT, U]] + + given mkIsHCons13[L[_], H[_], T[_] <: HList, FH[_[_]], FT[_[_], _[_]], U[_]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[FH, H], + ftt: => ApplyF[Apply11[FT, U], T], + ): IsHCons1.Aux[L, FH, Apply11[FT, U], H, T] = + IsHCons1.fromProduct[L, H, T, FH, Apply11[FT, U]] } trait IsHCons10ScalaCompat { - given fromProduct[L[_] <: Product, FH[_[_]], FT[_[_]]]( - using m: MirrorOf1Product[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesHCons[m.MirroredElemTypes]], - ): IsHCons1.Aux[L, FH, FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesHCons[m.MirroredElemTypes]] = new IsHCons1[L, FH, FT] { - override type H[Z] = Head[m.MirroredElemTypes[Z]] - override type T[Z] = HList.TupleToHList[Tail[m.MirroredElemTypes[Z]]] - - override def pack[A](u: (H[A], T[A])): L[A] = { - val t = u._1 *: HList.hListToTuple(u._2) - m.fromProduct(t).asInstanceOf[L[A]] + def apply[L[_], FH[_[_]], FT[_[_]]](using ev: IsHCons1[L, FH, FT]): IsHCons1.Aux[L, FH, FT, ev.H, ev.T] = + ev + + given fromProduct[L[_], H0[_], T0[_] <: HList, FH[_[_]], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H0, T0], + fhh: => ApplyF[FH, H0], + ftt: => ApplyF[FT, T0], + ): IsHCons1.Aux[L, FH, FT, H0, T0] = new IsHCons1[L, FH, FT] { + override type H[Z] = H0[Z] + override type T[Z] = T0[Z] + + override def pack[Z](u: (H[Z], T[Z])): L[Z] = + (u._1 :: u._2).asInstanceOf[L[Z]] + + override def unpack[Z](p: L[Z]): (H[Z], T[Z]) = { + val c = p.asInstanceOf[H[Z] :: T[Z]] + (c.head, c.tail) } - override def unpack[Z](p: L[Z]): (H[Z], T[Z]) = - //This is safe as the ftt won't be typed correctly if L produces an empty tuple - (scala.Tuple.fromProduct(p): @unchecked) match { - case h *: t => (h.asInstanceOf[H[Z]], HList.tupleToHList(t).asInstanceOf[T[Z]]) - } - override def mkFhh: FH[H] = fhh override def mkFtt: FT[T] = ftt } } -type TailElemTypesCCons[ElemTypes[_] <: scala.Tuple] = [Z] =>> Coproduct.TupleToCoproduct[Tail[ElemTypes[Z]]] - trait IsCCons1ScalaCompat extends IsCCons10 { - implicit def mkIsCCons10[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]( - using m: MirrorOf1Sum[L], - fhh: => ApplyF[Apply10[FH, U], HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], - ): IsCCons1.Aux[L, Apply10[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = - IsCCons1.fromSum[L, Apply10[FH, U], FT] - - implicit def mkIsCCons11[L[_], FH[_[_], _[_]], U[_], FT[_[_]]]( - using m: MirrorOf1Sum[L], - fhh: => ApplyF[Apply11[FH, U], HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], - ): IsCCons1.Aux[L, Apply11[FH, U], FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = - IsCCons1.fromSum[L, Apply11[FH, U], FT] - - implicit def mkIsCCons12[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]( - using m: MirrorOf1Sum[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[Apply10[FT, U], TailElemTypesCCons[m.MirroredElemTypes]], - ): IsCCons1.Aux[L, FH, Apply10[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = - IsCCons1.fromSum[L, FH, Apply10[FT, U]] - - implicit def mkIsCCons13[L[_], FH[_[_]], FT[_[_], _[_]], U[_]]( - using m: MirrorOf1Sum[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[Apply11[FT, U], TailElemTypesCCons[m.MirroredElemTypes]], - ): IsCCons1.Aux[L, FH, Apply11[FT, U], HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = - IsCCons1.fromSum[L, FH, Apply11[FT, U]] + implicit def mkIsCCons10[L[_], H[_], T[_] <: Coproduct, FH[_[_], _[_]], U[_], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[Apply10[FH, U], H], + ftt: => ApplyF[FT, T], + ): IsCCons1.Aux[L, Apply10[FH, U], FT, H, T] = + IsCCons1.fromSum[L, H, T, Apply10[FH, U], FT] + + implicit def mkIsCCons11[L[_], H[_], T[_] <: Coproduct, FH[_[_], _[_]], U[_], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[Apply11[FH, U], H], + ftt: => ApplyF[FT, T], + ): IsCCons1.Aux[L, Apply11[FH, U], FT, H, T] = + IsCCons1.fromSum[L, H, T, Apply11[FH, U], FT] + + implicit def mkIsCCons12[L[_], H[_], T[_] <: Coproduct, FH[_[_]], FT[_[_], _[_]], U[_]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[FH, H], + ftt: => ApplyF[Apply10[FT, U], T], + ): IsCCons1.Aux[L, FH, Apply10[FT, U], H, T] = + IsCCons1.fromSum[L, H, T, FH, Apply10[FT, U]] + + implicit def mkIsCCons13[L[_], H[_], T[_] <: Coproduct, FH[_[_]], FT[_[_], _[_]], U[_]]( + using splitCons: SplitCons.Aux[L, H, T], + fhh: => ApplyF[FH, H], + ftt: => ApplyF[Apply11[FT, U], T], + ): IsCCons1.Aux[L, FH, Apply11[FT, U], H, T] = + IsCCons1.fromSum[L, H, T, FH, Apply11[FT, U]] } trait IsCCons10ScalaCompat { - given fromSum[L[_], FH[_[_]], FT[_[_]]]( - using m: MirrorOf1Sum[L], - fhh: => ApplyF[FH, HeadElemTypes[m.MirroredElemTypes]], - ftt: => ApplyF[FT, TailElemTypesCCons[m.MirroredElemTypes]], - ): IsCCons1.Aux[L, FH, FT, HeadElemTypes[m.MirroredElemTypes], TailElemTypesCCons[m.MirroredElemTypes]] = new IsCCons1[L, FH, FT] { - override type H[Z] = Head[m.MirroredElemTypes[Z]] - override type T[Z] = Coproduct.TupleToCoproduct[Tail[m.MirroredElemTypes[Z]]] + def apply[L[_], FH[_[_]], FT[_[_]]](using ev: IsCCons1[L, FH, FT]): IsCCons1.Aux[L, FH, FT, ev.H, ev.T] = + ev + + given fromSum[L[_], H0[_], T0[_] <: Coproduct, FH[_[_]], FT[_[_]]]( + using splitCons: SplitCons.Aux[L, H0, T0], + fhh: => ApplyF[FH, H0], + ftt: => ApplyF[FT, T0], + ): IsCCons1.Aux[L, FH, FT, H0, T0] = new IsCCons1[L, FH, FT] { + override type H[Z] = H0[Z] + override type T[Z] = T0[Z] - override def pack[Z](u: Either[H[Z], T[Z]]): L[Z] = ??? /*u match { - case Left(hz) => ??? //hz.asInstanceOf[L[Z]] - case Right(tz) => ??? //Coproduct.extractCoproduct(tz).asInstanceOf[L[Z]] - }*/ + override def pack[Z](u: Either[H[Z], T[Z]]): L[Z] = u match { + case Left(h) => Inl(h).asInstanceOf[L[Z]] + case Right(t) => Inr(t).asInstanceOf[L[Z]] + } override def unpack[Z](p: L[Z]): Either[H[Z], T[Z]] = { - //TODO: Make sure this is correct - val ordinal = m.ordinal(p.asInstanceOf[m.MirroredMonoType]) - if ordinal == 0 then Left(p.asInstanceOf[H[Z]]) - else Right(Coproduct.coproductFromOrdinal(p.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes[Z]]], ordinal - 1).asInstanceOf[T[Z]]) + val c = p.asInstanceOf[H[Z] :+: T[Z]] + c match { + case Inl(head) => Left(head) + case Inr(tail) => Right(tail) + } } override def mkFhh: FH[H] = fhh @@ -241,3 +258,47 @@ trait Split1ScalaCompat extends Split10 { trait Split10ScalaCompat { implicit def apply[L[_], FO[_[_]], FI[_[_]]]: Split1[L, FO, FI] = ??? } + +trait SplitCons[L[_]] { + type H[_] + type T[_] +} +object SplitCons { + type Aux[L[_], H0[_], T0[_]] = SplitCons[L] { type H[A] = H0[A]; type T[A] = T0[A] } + + /* + given [H0[_], T0[_] <: HList]: SplitCons.Aux[[A] =>> H0[A] :: T0[A], H0, T0] = new SplitCons.Aux[[A] =>> H0[A] :: T0[A]] { + type H[A] = H0[A] + type T[A] = T0[A] + } + */ + + /* + import scala.quoted.* + + transparent inline given[L[_]]: SplitCons[L] = ${splitConsImpl[L]} + + private def splitConsImpl[L[_]: Type](using quotes: Quotes): Expr[SplitCons[L]] = { + import quotes.reflect.* + + Type.of[L] match { + case '[h :: t] => + '{ + new SplitCons[L] { + type H[X] = h[X] + type T[Y] = t[Y] + } + } + case '[h :+: t] => + '{ + new SplitCons[L] { + type H[X] = h[X] + type T[Y] = t[Y] + } + } + case _ => + report.throwError("Can't split higher kinded cons") + } + } + */ +} diff --git a/core/src/main/scala-3/shapeless/nat.scala b/core/src/main/scala-3/shapeless/nat.scala index de0779293..7a1d580e7 100644 --- a/core/src/main/scala-3/shapeless/nat.scala +++ b/core/src/main/scala-3/shapeless/nat.scala @@ -39,10 +39,10 @@ trait NatScalaCompat { trait NatWithTypeAtPosScalaCompat { //Transparent gives better types here - transparent inline implicit def fromIntList[L <: HList, Out](inline i: Int)(implicit at: ops.hlist.At.Aux[L, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[L] = + transparent inline implicit def fromIntList[L <: HList, I <: Int with Singleton, Out](inline i: I)(implicit at: ops.hlist.At.Aux[L, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[L] = if i < 0 then compiletime.error("Can't convert value less than 0 to nat") else { - type N0 = Nat.IntToNat[i.type] + type N0 = Nat.IntToNat[I] val n = Nat(i) new NatWithTypeAtPos[L] { @@ -53,10 +53,10 @@ trait NatWithTypeAtPosScalaCompat { } //Transparent gives better types here - transparent inline implicit def fromIntTuple[T <: scala.Tuple, Out](inline i: Int)(implicit at: ops.tuple.At.Aux[T, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[T] = + transparent inline implicit def fromIntTuple[T <: scala.Tuple, I <: Int with Singleton, Out](inline i: I)(implicit at: ops.tuple.At.Aux[T, Nat.IntToNat[i.type], Out]): NatWithTypeAtPos[T] = if i < 0 then compiletime.error("Can't convert value less than 0 to nat") else { - type N0 = Nat.IntToNat[i.type] + type N0 = Nat.IntToNat[I] val n = Nat(i) new NatWithTypeAtPos[T] { diff --git a/core/src/main/scala-3/shapeless/ops/record/records.scala b/core/src/main/scala-3/shapeless/ops/record/records.scala index 2bae27d9c..461c96ed0 100644 --- a/core/src/main/scala-3/shapeless/ops/record/records.scala +++ b/core/src/main/scala-3/shapeless/ops/record/records.scala @@ -30,7 +30,7 @@ type FindField0[R <: HList, K, I <: Int] <: (Any, Int) = R match { trait SelectorScalaCompat { - given[R <: HList, K]( + transparent inline given[R <: HList, K]( using idx: ValueOf[scala.Tuple.Elem[FindField[R, K], 1]] ): Selector.Aux[R, K, scala.Tuple.Head[FindField[R, K]]] = new UnsafeSelector(idx.value).asInstanceOf[Selector.Aux[R, K, scala.Tuple.Head[FindField[R, K]]]] @@ -55,7 +55,7 @@ type IfEq[A, B, IfTrue, IfFalse] <: IfTrue | IfFalse = A match { trait UpdaterScalaCompat { - given [L <: HList, F]( + transparent inline given [L <: HList, F]( using idx: ValueOf[IndexOf[L, F]] ): Updater.Aux[L, F, IfEq[IndexOf[L, F], -1, Append[L, F], L]] = new UnsafeUpdater(idx.value).asInstanceOf[Updater.Aux[L, F, IfEq[IndexOf[L, F], -1, Append[L, F], L]]] @@ -68,7 +68,7 @@ type ReplaceField[R <: HList, K, B] <: HList = R match { } trait ModifierScalaCompat { - given [R <: HList, K, A, B]( + transparent inline given [R <: HList, K, A, B]( using ev: scala.Tuple.Head[FindField[R, K]] <:< A, idx: ValueOf[scala.Tuple.Elem[FindField[R, K], 1]] ): Modifier.Aux[R, K, A, B, ReplaceField[R, K, B]] = @@ -87,7 +87,7 @@ type RemoveField0[R <: HList, K, I <: Int, Acc <: HList] <: (Int, Any, HList) = } trait RemoverScalaCompat { - given [R <: HList, K]( + transparent inline given [R <: HList, K]( using idx: ValueOf[scala.Tuple.Head[RemoveField[R, K]]] ): Remover.Aux[R, K, scala.Tuple.Tail[RemoveField[R, K]]] = new UnsafeRemover(idx.value).asInstanceOf[Remover.Aux[R, K, scala.Tuple.Tail[RemoveField[R, K]]]] @@ -100,5 +100,5 @@ type HasNoKey[R <: HList, K] <: Boolean = R match { } trait LacksKeyScalaCompat { - given [R <: HList, K](using HasNoKey[R, K] =:= true): LacksKey[R, K] = new LacksKey[R, K] + transparent inline given [R <: HList, K](using HasNoKey[R, K] =:= true): LacksKey[R, K] = new LacksKey[R, K] } diff --git a/core/src/main/scala-3/shapeless/refute.scala b/core/src/main/scala-3/shapeless/refute.scala new file mode 100644 index 000000000..72a71b447 --- /dev/null +++ b/core/src/main/scala-3/shapeless/refute.scala @@ -0,0 +1,18 @@ +package shapeless + +import scala.util.NotGiven + +/** Evidence that no implicit instance of type `T` is available + * + * @author Zainab Ali + */ +@annotation.implicitNotFound(msg = "Implicit instance for ${T} in scope.") +trait Refute[T] +object Refute { + + /** This always declares an instance of `Refute` + * + * This instance will only be found when there is no evidence of `T` + * */ + implicit def refute[T](implicit dummy: NotGiven[T]): Refute[T] = new Refute[T] {} +} diff --git a/core/src/main/scala-3/shapeless/test/illTyped.scala b/core/src/main/scala-3/shapeless/test/illTyped.scala index ab64fc6fd..16729495f 100644 --- a/core/src/main/scala-3/shapeless/test/illTyped.scala +++ b/core/src/main/scala-3/shapeless/test/illTyped.scala @@ -3,35 +3,67 @@ package shapeless.test import java.util.regex.Pattern import scala.compiletime.* import scala.compiletime.testing.* +import scala.quoted.* object illTyped { - inline def apply(inline code: String): Unit = { - val errors = typeCheckErrors(code) - errors.find(_.kind == ErrorKind.Parser).foreach { e => - error(s"Parsing failed.\n${e.message}") + inline def apply(inline code: String): Unit = + ${impl('{typeCheckErrors(code)}, '{None})} + + inline def apply(inline code: String, inline expected: String): Unit = + ${impl('{typeCheckErrors(code)}, '{Some(expected)})} + + private given FromExpr[ErrorKind] with { + override def unapply(x: Expr[ErrorKind])(using Quotes): Option[ErrorKind] = x match { + case '{ErrorKind.Parser} => Some(ErrorKind.Parser) + case '{ErrorKind.Typer} => Some(ErrorKind.Typer) + case _ => None } + } - if (errors.isEmpty) { - error("Type-checking succeeded unexpectedly.\nExpected some error.") + private given FromExpr[Error] with { + override def unapply(x: Expr[Error])(using Quotes): Option[Error] = { + x match { + case '{Error($a, $b, $c, $d)} => + (a.asExprOf[String], b.asExprOf[String], c.asExprOf[Int], d.asExprOf[ErrorKind]) match { + case (Expr(message), Expr(lineContent), Expr(column), Expr(errorKind)) => + Some(Error(message, lineContent, column, errorKind)) + case _ => None + } + case _ => None + } } } - inline def apply(inline code: String, inline expected: String): Unit = { - val errors = typeCheckErrors(code) + def impl(errorsE: Expr[List[Error]], expectedE: Expr[Option[String]])(using quotes: Quotes): Expr[Unit] = { + import quotes.reflect.* - val expectedPattern: Pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) + val errors = errorsE.asTerm match { + case Inlined(_, _, Apply(_, List(errorsVararg))) => + errorsVararg.asExprOf[Seq[Error]] match { + case Varargs(Exprs(es)) => es + case _ => report.throwError("Unexpected errors structure") + } + case _ => report.throwError("Unexpected errors structure") + } + val expectedOpt = expectedE.valueOrError errors.find(_.kind == ErrorKind.Parser).foreach { e => - error(s"Parsing failed.\n${e.message}") + report.throwError("Parsing failed.\n" + e.message) } if (errors.isEmpty) { - error("Type-checking succeeded unexpectedly.\nExpected some error.") + report.throwError("Type-checking succeeded unexpectedly.\nExpected some error.") } - if (!errors.exists(e => expectedPattern.matcher(e.message).matches)) { - error("Type-checking failed in an unexpected way.\n" + expected + "\nActual error: "+ errors.head.message) + expectedOpt.foreach { expected => + val expectedPattern: Pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) + + if (!errors.exists(e => expectedPattern.matcher(e.message).matches)) { + report.throwError("Type-checking failed in an unexpected way.\n" + expected + "\nActual error: "+ errors.head.message) + } } + + '{()} } } diff --git a/core/src/main/scala-3/shapeless/test/types.scala b/core/src/main/scala-3/shapeless/test/types.scala index 40c0dafd6..da938527a 100644 --- a/core/src/main/scala-3/shapeless/test/types.scala +++ b/core/src/main/scala-3/shapeless/test/types.scala @@ -10,4 +10,13 @@ inline def showType[T]: String = ${showTypeImpl[T]} inline def showType[T](t: => T): String = ${showTypeImpl[T]} -private def showTypeImpl[T: Type](using Quotes): Expr[String] = Expr(Type.show[T]) +private def showTypeImpl[T: Type](using quotes: Quotes): Expr[String] = { + import quotes.reflect.* + Expr(TypeRepr.of[T].dealias.show) +} + +inline def desugared[T](inline expr: T): String = ${desugaredImpl('{expr})} + +private def desugaredImpl[T](expr: Expr[T])(using Quotes): Expr[String] = + import quotes.reflect.* + Expr(expr.show) diff --git a/core/src/main/scala-3/shapeless/typeoperators.scala b/core/src/main/scala-3/shapeless/typeoperators.scala index a624face7..4f878727d 100644 --- a/core/src/main/scala-3/shapeless/typeoperators.scala +++ b/core/src/main/scala-3/shapeless/typeoperators.scala @@ -1,5 +1,5 @@ package shapeless trait theScalaCompat { - transparent inline def the[T](using inline x: T): x.type = x + transparent inline def apply[T](using inline x: T): x.type = x } diff --git a/core/src/main/scala/shapeless/Testing3.scala b/core/src/main/scala/shapeless/Testing3.scala new file mode 100644 index 000000000..8d03b3b7f --- /dev/null +++ b/core/src/main/scala/shapeless/Testing3.scala @@ -0,0 +1,83 @@ +package shapeless + +import shapeless.nat._ + +import scala.deriving.Mirror +import scala.annotation.Annotation as saAnnotation +import shapeless.NotContainsConstraint.NotContains +import shapeless.labelled.->> +import shapeless.ops.coproduct.{ExtendRight, ExtendRightBy} +import shapeless.ops.hlist.{SelectAll, ToSized} +import shapeless.ops.nat.Sum +import shapeless.ops.record.{Extractor, Remover} +import shapeless.test.{illTyped, typed} + +@main def testing: Unit = { + type R = ("a" ->> Int) :: ("b" ->> String) :: HNil + /* + type RM1 = ("a" ->> Int) :: HNil + + val r = Remover[R, "a"] + val e1 = Extractor[R, RM1]( + Extractor.extract( + summon, + summon, + summon, + summon, + ) + ) + */ + + /* + val e2 = ExtendRightBy[Boolean :+: CNil, String :+: Boolean :+: CNil]( + ExtendRightBy.extendRightByCoproduct( + summon[ExtendRight[Boolean :+: CNil, String]], + summon + ) + ) + */ + + //SelectAll[R, ("a" ->> Int) :: HNil] + //SelectAll[("a" ->> Int) :: ("b" ->> Boolean) :: ("c" ->> String) :: HNil] + + /* + object toInt extends Poly1 { + implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) + } + + + def range[R <: HList](a: Nat, b: Nat)(implicit + range: ops.nat.Range.Aux[a.N, b.N, R], + mapper: ops.hlist.Mapper[toInt.type, R] + ) = mapper(range()) + + (0, 1) ::(2, 3) ::(4, 'a') :: HNil == range(0, 5).group(2, 2, 'a' :: HNil) + (0, 1) ::(2, 3) ::(4, 'a') :: HNil == range(0, 5).group(2, 2, 'a' :: 'b' :: 'c' :: HNil) + */ + + /* + trait MyNat + case class Succ[P <: MyNat]() extends MyNat + class _0 extends MyNat + + trait MySum[A <: MyNat, B <: MyNat] extends Serializable { type Out <: MyNat } + object MySum { + def apply[A <: MyNat, B <: MyNat](implicit sum: MySum[A, B]): Aux[A, B, sum.Out] = sum + + type Aux[A <: MyNat, B <: MyNat, C <: MyNat] = MySum[A, B] { type Out = C } + + implicit def sum1[B <: MyNat]: Aux[_0, B, B] = new MySum[_0, B] { type Out = B } + implicit def sum2[A <: MyNat, B <: MyNat, C <: MyNat] + (implicit sum : MySum.Aux[A, Succ[B], C]): MySum.Aux[Succ[A], B, C] = new MySum[Succ[A], B] { type Out = C } + } + import MySum.{sum1, sum2} + + //implicitly[MySum.Aux[Succ[Succ[_0]], Succ[_0], Succ[Succ[Succ[_0]]]]] + + import Sum.{sum1, sum2} + scala.compiletime.ops.int + + implicitly[Sum.Aux[_2, _1, _3]] + //implicitly[Sum.Aux[_2, _3, _5]] + */ +} diff --git a/core/src/test/scala-2/shapeless/annotations.scala b/core/src/test/scala-2/shapeless/annotations.scala new file mode 100644 index 000000000..118ec7b2e --- /dev/null +++ b/core/src/test/scala-2/shapeless/annotations.scala @@ -0,0 +1,15 @@ +package shapeless + +import scala.annotation.{ Annotation => saAnnotation } +import org.junit.Test +import shapeless.test.{illTyped, typed} + +class AnnotationTestsScala2 { + import AnnotationTestsDefinitions._ + + @Test + def allTypeAnnotations: Unit = { + val st = AllTypeAnnotations[Base2].apply() // sealed trait + typed[(First :: HNil) :: (Second :: Third :: HNil) :: HNil](st) + } +} diff --git a/core/src/test/scala-2/shapeless/conversions.scala b/core/src/test/scala-2/shapeless/conversions.scala new file mode 100644 index 000000000..111b7b3e9 --- /dev/null +++ b/core/src/test/scala-2/shapeless/conversions.scala @@ -0,0 +1,26 @@ +package shapeless + +import org.junit.Test +import org.junit.Assert._ + +class ConversionsTestsScala2 { + import ops.function.{ FnToProduct, FnFromProduct } + import syntax.std.function._ + import syntax.std.tuple._ + import test._ + + @Test + def testFunctions: Unit = { + class HListSyntax[A <: HList, F <: AnyRef](a: A) { + def applied[U](f: F)(implicit cftp: FnToProduct.Aux[f.type, A => U]): U = cftp(f)(a) + } + + implicit def mkSyntax[A <: HList, F <: AnyRef](a: A) + (implicit ffp: FnFromProduct.Aux[A => Any, F]): HListSyntax[A, F] = + new HListSyntax[A, F](a) + + val res = (2 :: "a" :: 1.3 :: HNil) applied ((i, s, d) => (s * i, d * i)) // Function argument types inferred + + assert((res: (String, Double)) == ("aa", 2.6)) + } +} diff --git a/core/src/test/scala-2/shapeless/generic.scala b/core/src/test/scala-2/shapeless/generic.scala new file mode 100644 index 000000000..29d562808 --- /dev/null +++ b/core/src/test/scala-2/shapeless/generic.scala @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2013-15 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import org.junit.Test +import org.junit.Assert._ + +import ops.{ hlist => hl, coproduct => cp } +import testutil.assertTypedEquals +import test.illTyped + +package GenericTestsAux { + + sealed trait AbstractNonCC + class NonCCA(val i: Int, val s: String) extends AbstractNonCC + class NonCCB(val b: Boolean, val d: Double) extends AbstractNonCC + class NonCCWithVars(var c: Char, var l: Long) extends AbstractNonCC + class NonCCWithVal(val n: Int) extends AbstractNonCC { + val isEven: Boolean = n % 2 == 0 + } + + class NonCCWithCompanion private (val i: Int, val s: String) + object NonCCWithCompanion { + def apply(i: Int, s: String) = new NonCCWithCompanion(i, s) + def unapply(s: NonCCWithCompanion): Option[(Int, String)] = Some((s.i, s.s)) + } + + class NonCCLazy(prev0: => NonCCLazy, next0: => NonCCLazy) { + lazy val prev = prev0 + lazy val next = next0 + } + + sealed trait Overlapping + sealed trait OA extends Overlapping + case class OAC(s: String) extends OA + sealed trait OB extends Overlapping + case class OBC(s: String) extends OB + case class OAB(i: Int) extends OA with OB + + class CCLikeOrdered[A: Ordering](val value: A) + + class CCLikeDegen(val i: Int)() + + class Squared(x: Long) { + val x2 = x * x + } + + type TapRepr[A] = ConstTap[A] :+: InTap[A, _] :+: OutTap[A, _] :+: PipeTap[A, _] :+: CNil +} + +class GenericScala2Tests { + import GenericTestsAux._ + import scala.collection.immutable.{ :: => Cons } + import test._ + + @Test + def testAbstractNonCC: Unit = { + val ncca = new NonCCA(23, "foo") + val nccb = new NonCCB(true, 2.0) + val nccc = new NonCCWithVars('c', 42) + val nccd = new NonCCWithVal(313) + val ancc: AbstractNonCC = ncca + + val genA = Generic[NonCCA] + val genB = Generic[NonCCB] + val genC = Generic[NonCCWithVars] + val genD = Generic[NonCCWithVal] + val genAbs = Generic[AbstractNonCC] + + val rA = genA.to(ncca) + assertTypedEquals[Int :: String :: HNil](23 :: "foo" :: HNil, rA) + + val rB = genB.to(nccb) + assertTypedEquals[Boolean :: Double :: HNil](true :: 2.0 :: HNil, rB) + + val rC = genC.to(nccc) + assertTypedEquals[Char :: Long :: HNil]('c' :: 42L :: HNil, rC) + + val rD = genD.to(nccd) + assertTypedEquals[Int :: HNil](313 :: HNil, rD) + + val rAbs = genAbs.to(ancc) + assertTypedEquals[NonCCA :+: NonCCB :+: NonCCWithVars :+: NonCCWithVal :+: CNil](Inl(ncca), rAbs) + + val fA = genA.from(13 :: "bar" :: HNil) + typed[NonCCA](fA) + assertEquals(13, fA.i) + assertEquals("bar", fA.s) + + val fB = genB.from(false :: 3.0 :: HNil) + typed[NonCCB](fB) + assertEquals(false, fB.b) + assertEquals(3.0, fB.d, Double.MinPositiveValue) + + val fC = genC.from('k' :: 313L :: HNil) + typed[NonCCWithVars](fC) + assertEquals('k', fC.c) + assertEquals(313L, fC.l) + + val fD = genD.from(99 :: HNil) + typed[NonCCWithVal](fD) + assertEquals(99, fD.n) + + val fAbs = genAbs.from(Inr(Inl(nccb))) + typed[AbstractNonCC](fAbs) + assertTrue(fAbs.isInstanceOf[NonCCB]) + assertEquals(true, fAbs.asInstanceOf[NonCCB].b) + assertEquals(2.0, fAbs.asInstanceOf[NonCCB].d, Double.MinPositiveValue) + } + + @Test + def testNonCCWithCompanion: Unit = { + val nccc = NonCCWithCompanion(23, "foo") + + val gen = Generic[NonCCWithCompanion] + + val r = gen.to(nccc) + assertTypedEquals[Int :: String :: HNil](23 :: "foo" :: HNil, r) + + val f = gen.from(13 :: "bar" :: HNil) + typed[NonCCWithCompanion](f) + assertEquals(13, f.i) + assertEquals("bar", f.s) + } + + @Test + def testNonCCLazy: Unit = { + lazy val (a: NonCCLazy, b: NonCCLazy, c: NonCCLazy) = + (new NonCCLazy(c, b), new NonCCLazy(a, c), new NonCCLazy(b, a)) + + val gen = Generic[NonCCLazy] + + val rB = gen.to(b) + assertTypedEquals[NonCCLazy :: NonCCLazy :: HNil](a :: c :: HNil, rB) + + val fD = gen.from(a :: c :: HNil) + typed[NonCCLazy](fD) + assertEquals(a, fD.prev) + assertEquals(c, fD.next) + } + + @Test + def testOverlappingCoproducts: Unit = { + val gen = Generic[Overlapping] + val o: Overlapping = OAB(1) + val o0 = gen.to(o) + typed[OAC :+: OAB :+: OBC :+: CNil](o0) + + val o1 = gen.from(o0) + typed[Overlapping](o1) + } + + trait Parent { + case class Nested(i: Int, s: String) + + sealed abstract class Foo extends Product with Serializable + + case object A extends Foo + case object B extends Foo + case class C() extends Foo + } + + trait Child extends Parent { + val gen = Generic[Nested] + val adtGen = Generic[Foo] + } + + object O extends Child + + @Test + def testNestedInherited: Unit = { + val n0 = O.Nested(23, "foo") + val repr = O.gen.to(n0) + typed[Int :: String :: HNil](repr) + val n1 = O.gen.from(repr) + typed[O.Nested](n1) + assertEquals(n0, n1) + + { + val foo0 = O.B + val repr = O.adtGen.to(foo0) + typed[O.A.type :+: O.B.type :+: O.C :+: CNil](repr) + } + + { + val foo0 = O.C() + val repr = O.adtGen.to(foo0) + typed[O.A.type :+: O.B.type :+: O.C :+: CNil](repr) + } + } + + @Test + def testPathViaSubPrefix: Unit = { + class Outer { + class Inner { + sealed trait T + } + + val inner = new Inner + case class C(i: Int) extends inner.T + case object O extends inner.T + } + + val outer = new Outer + type Repr = outer.C :+: outer.O.type :+: CNil + val gen = Generic[outer.inner.T] + val c = outer.C(42) + val injC: Repr = Inl(c) + val injO: Repr = Inr(Inl(outer.O)) + + assertTypedEquals[Repr](injC, gen.to(c)) + assertTypedEquals[outer.inner.T](c, gen.from(injC)) + assertTypedEquals[Repr](injO, gen.to(outer.O)) + assertTypedEquals[outer.inner.T](outer.O, gen.from(injO)) + } + + @Test + def testGenericImplicitParams: Unit = { + type Repr = Int :: HNil + val gen = Generic[CCOrdered[Int]] + val cc = CCOrdered(42) + val rep = 42 :: HNil + + assertTypedEquals[CCOrdered[Int]](gen.from(rep), cc) + assertTypedEquals[Repr](gen.to(cc), rep) + illTyped("Generic[CCLikeOrdered[Int]]") + } + + @Test + def testGenericDegenerate: Unit = { + type Repr = Int :: HNil + val gen = Generic[CCDegen] + val cc = CCDegen(313)() + val rep = 313 :: HNil + + assertTypedEquals[CCDegen](gen.from(rep), cc) + assertTypedEquals[Repr](gen.to(cc), rep) + illTyped("Generic[CCLikeDegen]") + } +} + +object MixedCCNonCCNested { + // Block local + { + object T1{ + sealed abstract class Tree + final case class Node(left: Tree, right: Tree, v: Int) extends Tree + case object Leaf extends Tree + } + + Generic[T1.Tree] + import T1._ + Generic[Tree] + + sealed trait A + sealed case class B(i: Int, s: String) extends A + case object C extends A + sealed trait D extends A + final case class E(a: Double, b: Option[Float]) extends D + case object F extends D + sealed abstract class Foo extends D + case object Baz extends Foo + final class Bar extends Foo + final class Baz(val i1: Int, val s1: String) extends Foo + + Generic[A] + Generic[B] + Generic[C.type] + Generic[D] + Generic[E] + Generic[F.type] + Generic[Foo] + Generic[Baz.type] + Generic[Bar] + Generic[Baz] + } + + def methodLocal: Unit = { + object T1{ + sealed abstract class Tree + final case class Node(left: Tree, right: Tree, v: Int) extends Tree + case object Leaf extends Tree + } + + Generic[T1.Tree] + import T1._ + Generic[Tree] + + sealed trait A + sealed case class B(i: Int, s: String) extends A + case object C extends A + sealed trait D extends A + final case class E(a: Double, b: Option[Float]) extends D + case object F extends D + sealed abstract class Foo extends D + case object Baz extends Foo + final class Bar extends Foo + final class Baz(val i1: Int, val s1: String) extends Foo + + Generic[A] + Generic[B] + Generic[C.type] + Generic[D] + Generic[E] + Generic[F.type] + Generic[Foo] + Generic[Baz.type] + Generic[Bar] + Generic[Baz] + } + + // Top level + object T1{ + sealed abstract class Tree + final case class Node(left: Tree, right: Tree, v: Int) extends Tree + case object Leaf extends Tree + } + + Generic[T1.Tree] + import T1._ + Generic[Tree] + + sealed trait A + sealed case class B(i: Int, s: String) extends A + case object C extends A + sealed trait D extends A + final case class E(a: Double, b: Option[Float]) extends D + case object F extends D + sealed abstract class Foo extends D + case object Baz extends Foo + final class Bar extends Foo + final class Baz(val i1: Int, val s1: String) extends Foo + + Generic[A] + Generic[B] + Generic[C.type] + Generic[D] + Generic[E] + Generic[F.type] + Generic[Foo] + Generic[Baz.type] + Generic[Bar] + Generic[Baz] +} + +object EnumDefns0 { + sealed trait EnumVal + val BarA = new EnumVal { val name = "A" } + val BarB = new EnumVal { val name = "B" } + val BarC = new EnumVal { val name = "C" } +} + +object EnumDefns3 { + sealed trait EnumVal + val BarA, BarB, BarC = new EnumVal {} +} + +object EnumDefns4 { + sealed trait EnumVal + object EnumVal { + val BarA = new EnumVal { val name = "A" } + val BarB = new EnumVal { val name = "B" } + val BarC = new EnumVal { val name = "C" } + } +} + +object EnumDefns7 { + sealed trait EnumVal + object EnumVal { + val BarA, BarB, BarC = new EnumVal {} + } +} + +class TestEnumScala2 { + @Test + def testEnum0: Unit = { + import EnumDefns0._ + + val gen = Generic[EnumVal] + val a0 = gen.to(BarA) + assert(a0 == Inl(BarA)) + + val b0 = gen.to(BarB) + assert(b0 == Inr(Inl(BarB))) + + val c0 = gen.to(BarC) + assert(c0 == Inr(Inr(Inl(BarC)))) + } + + @Test + def testEnum3: Unit = { + import EnumDefns3._ + + val gen = Generic[EnumVal] + val a0 = gen.to(BarA) + assert(a0 == Inl(BarA)) + + val b0 = gen.to(BarB) + assert(b0 == Inr(Inl(BarB))) + + val c0 = gen.to(BarC) + assert(c0 == Inr(Inr(Inl(BarC)))) + } + + @Test + def testEnum4: Unit = { + import EnumDefns4._ + import EnumVal._ + + val gen = Generic[EnumVal] + val a0 = gen.to(BarA) + assert(a0 == Inl(BarA)) + + val b0 = gen.to(BarB) + assert(b0 == Inr(Inl(BarB))) + + val c0 = gen.to(BarC) + assert(c0 == Inr(Inr(Inl(BarC)))) + } + + @Test + def testEnum7: Unit = { + import EnumDefns7._ + import EnumVal._ + + val gen = Generic[EnumVal] + val a0 = gen.to(BarA) + assert(a0 == Inl(BarA)) + + val b0 = gen.to(BarB) + assert(b0 == Inr(Inl(BarB))) + + val c0 = gen.to(BarC) + assert(c0 == Inr(Inr(Inl(BarC)))) + } +} + +package TestPrefixes1 { + + object DerivationsScala2 { + import shapeless._ + + Generic[Defs.Sum] + Generic.materialize[Defs.Sum, Defs.SumI :+: Defs.SumS :+: CNil] + } +} + +object PathVariantDefns { + sealed trait AtomBase { + sealed trait Atom + case class Zero(value: String) extends Atom + } + + trait Atom1 extends AtomBase { + case class One(value: String) extends Atom + } + + trait Atom2 extends AtomBase { + case class Two(value: String) extends Atom + } + + object Atoms01 extends AtomBase with Atom1 + object Atoms02 extends AtomBase with Atom2 +} + +object PathVariants { + import PathVariantDefns._ + + val gen1 = Generic[Atoms01.Atom] + implicitly[gen1.Repr =:= (Atoms01.Zero :+: Atoms01.One :+: CNil)] + + val gen2 = Generic[Atoms02.Atom] + implicitly[gen2.Repr =:= (Atoms02.Zero :+: Atoms02.Two :+: CNil)] +} + +object Thrift { + object TProduct { + def apply(a: Double, b: String): TProduct = new Immutable(a, b) + + def unapply(tp: TProduct): Option[Product2[Double, String]] = Some(tp) + + //class Immutable(val a: Double, val b: String) extends TProduct + + class Immutable( + val a: Double, + val b: String, + val _passthroughFields: scala.collection.immutable.Map[Short, Byte] + ) extends TProduct { + def this( + a: Double, + b: String + ) = this( + a, + b, + Map.empty + ) + } + } + + trait TProduct extends Product2[Double, String] { + def a: Double + def b: String + + def _1 = a + def _2 = b + + override def productPrefix: String = "TProduct" + + def canEqual(t: Any): Boolean = true + } + + Generic[TProduct.Immutable] +} diff --git a/core/src/test/scala/shapeless/generic1.scala b/core/src/test/scala-2/shapeless/generic1.scala similarity index 97% rename from core/src/test/scala/shapeless/generic1.scala rename to core/src/test/scala-2/shapeless/generic1.scala index 0bbf703a0..e09b9581f 100644 --- a/core/src/test/scala/shapeless/generic1.scala +++ b/core/src/test/scala-2/shapeless/generic1.scala @@ -158,15 +158,15 @@ package Generic1TestsAux { } implicit def isCPointedSingleSingleton[C]( - implicit w: ValueOf[C], pf: => Pointed[Const[C]#λ] - ): Pointed[({type λ[A] = Const[C]#λ[A] :+: Const[CNil]#λ[A] })#λ] = + implicit w: ValueOf[C], pf: => Pointed[Const[C]#λ] + ): Pointed[({type λ[A] = Const[C]#λ[A] :+: Const[CNil]#λ[A] })#λ] = new Pointed[({type λ[A] = Const[C]#λ[A] :+: Const[CNil]#λ[A] })#λ] { def point[A](a: A): Const[C]#λ[A] :+: Const[CNil]#λ[A] = Inl(pf.point(a)) } implicit def isCPointedSingle[F[_]]( - implicit pf: => Pointed[F] - ): Pointed[({type λ[A] = F[A] :+: Const[CNil]#λ[A] })#λ] = + implicit pf: => Pointed[F] + ): Pointed[({type λ[A] = F[A] :+: Const[CNil]#λ[A] })#λ] = new Pointed[({type λ[A] = F[A] :+: Const[CNil]#λ[A] })#λ] { def point[A](a: A): F[A] :+: Const[CNil]#λ[A] = Inl(pf.point(a)) } @@ -291,7 +291,7 @@ class Generic1Tests { val gen = Generic1[Overlapping1, TC1] val o: Overlapping1[Int] = OAB1(1) val o0 = gen.to(o) - typed[OAB1[Int] :+: OAC1[Int] :+: OBC1[Int] :+: CNil](o0) + typed[OAC1[Int] :+: OAB1[Int] :+: OBC1[Int] :+: CNil](o0) val s1 = gen.from(o0) typed[Overlapping1[Int]](s1) diff --git a/core/src/test/scala-2/shapeless/hlist.scala b/core/src/test/scala-2/shapeless/hlist.scala new file mode 100644 index 000000000..14a6de825 --- /dev/null +++ b/core/src/test/scala-2/shapeless/hlist.scala @@ -0,0 +1,18 @@ +package shapeless + +import org.junit.Assert.assertEquals +import org.junit.Test + +trait HListTestsScalaCompat { this: HListTests => + + type PWS = Product with Serializable with Fruit + + type IntStringDoubleBound >: Double with Int with String + type AnyOrMatchable = Any + + @Test + def testToProductScala2 = { + import syntax.std.tuple._ + assertEquals(HNil, ().toHList) + } +} diff --git a/core/src/test/scala/shapeless/implicits.scala b/core/src/test/scala-2/shapeless/implicits.scala similarity index 90% rename from core/src/test/scala/shapeless/implicits.scala rename to core/src/test/scala-2/shapeless/implicits.scala index 9725a3cf5..59690aa9b 100644 --- a/core/src/test/scala/shapeless/implicits.scala +++ b/core/src/test/scala-2/shapeless/implicits.scala @@ -46,14 +46,14 @@ object CachedTestDefns { } implicit def eqGeneric[T, R] - (implicit - gen: Generic.Aux[T, R], - eqRepr: => Eq[R] - ): Eq[T] = - new Eq[T] { - def eqv(x: T, y: T): Boolean = - eqRepr.eqv(gen.to(x), gen.to(y)) - } + (implicit + gen: Generic.Aux[T, R], + eqRepr: => Eq[R] + ): Eq[T] = + new Eq[T] { + def eqv(x: T, y: T): Boolean = + eqRepr.eqv(gen.to(x), gen.to(y)) + } // Base case for products implicit val eqHNil: Eq[HNil] = new Eq[HNil] { @@ -62,14 +62,14 @@ object CachedTestDefns { // Induction step for products implicit def eqHCons[H, T <: HList] - (implicit - eqH: => Eq[H], - eqT: => Eq[T] - ): Eq[H :: T] = - new Eq[H :: T] { - def eqv(x: H :: T, y: H :: T): Boolean = - eqH.eqv(x.head, y.head) && eqT.eqv(x.tail, y.tail) - } + (implicit + eqH: => Eq[H], + eqT: => Eq[T] + ): Eq[H :: T] = + new Eq[H :: T] { + def eqv(x: H :: T, y: H :: T): Boolean = + eqH.eqv(x.head, y.head) && eqT.eqv(x.tail, y.tail) + } } implicit class EqOps[T](x: T)(implicit eqT: Eq[T]) { diff --git a/core/src/test/scala-2/shapeless/labelledgeneric.scala b/core/src/test/scala-2/shapeless/labelledgeneric.scala new file mode 100644 index 000000000..fd00c0f74 --- /dev/null +++ b/core/src/test/scala-2/shapeless/labelledgeneric.scala @@ -0,0 +1,104 @@ +package shapeless + +import org.junit.Test +import org.junit.Assert._ + +import ops.record._ +import record._ +import syntax.singleton._ +import test._ +import testutil._ +import union._ +import labelled.->> + +class LabelledGenericTestsScala2 { + import LabelledGenericTestsAux._ + + @Test + def testAbstractNonCC: Unit = { + val ncca = new NonCCA(23, "foo") + val nccb = new NonCCB(true, 2.0) + val ancc: AbstractNonCC = ncca + + type NonCCARec = ("i" ->> Int) :: ("s" ->> String) :: HNil + type NonCCBRec = ("b" ->> Boolean) :: ("d" ->> Double) :: HNil + type AbsUnion = ("NonCCA" ->> NonCCA) :+: ("NonCCB" ->> NonCCB) :+: CNil + + val genA = LabelledGeneric[NonCCA] + val genB = LabelledGeneric[NonCCB] + val genAbs = LabelledGeneric[AbstractNonCC] + + val rA = genA.to(ncca) + assertTypedEquals[NonCCARec]("i" ->> 23 :: "s" ->> "foo" :: HNil, rA) + + val rB = genB.to(nccb) + assertTypedEquals[NonCCBRec]("b" ->> true :: "d" ->> 2.0 :: HNil, rB) + + val rAbs = genAbs.to(ancc) + val injA = Coproduct[AbsUnion]("NonCCA" ->> ncca) + assertTypedEquals[AbsUnion](injA, rAbs) + + val fA = genA.from("i" ->> 13 :: "s" ->> "bar" :: HNil) + typed[NonCCA](fA) + assertEquals(13, fA.i) + assertEquals("bar", fA.s) + + val fB = genB.from("b" ->> false :: "d" ->> 3.0 :: HNil) + typed[NonCCB](fB) + assertEquals(false, fB.b) + assertEquals(3.0, fB.d, Double.MinPositiveValue) + + val injB = Coproduct[AbsUnion]("NonCCB" ->> nccb) + val fAbs = genAbs.from(injB) + typed[AbstractNonCC](fAbs) + assertTrue(fAbs.isInstanceOf[NonCCB]) + assertEquals(true, fAbs.asInstanceOf[NonCCB].b) + assertEquals(2.0, fAbs.asInstanceOf[NonCCB].d, Double.MinPositiveValue) + } + + @Test + def testNonCCWithCompanion: Unit = { + val nccc = NonCCWithCompanion(23, "foo") + + val rec = ("i" ->> 23) :: ("s" ->> "foo") :: HNil + type NonCCRec = ("i" ->> Int) :: ("s" ->> String) :: HNil + + val gen = LabelledGeneric[NonCCWithCompanion] + + val r = gen.to(nccc) + assertTypedEquals[NonCCRec](rec, r) + + val f = gen.from("i" ->> 13 :: "s" ->> "bar" :: HNil) + typed[NonCCWithCompanion](f) + assertEquals(13, f.i) + assertEquals("bar", f.s) + } + + @Test + def testNonCCLazy: Unit = { + lazy val (a: NonCCLazy, b: NonCCLazy, c: NonCCLazy) = + (new NonCCLazy(c, b), new NonCCLazy(a, c), new NonCCLazy(b, a)) + + val rec = "prev" ->> a :: "next" ->> c :: HNil + type LazyRec = ("prev" ->> NonCCLazy) :: ("next" ->> NonCCLazy) :: HNil + + val gen = LabelledGeneric[NonCCLazy] + + val rB = gen.to(b) + assertTypedEquals[LazyRec](rec, rB) + + val fD = gen.from("prev" ->> a :: "next" ->> c :: HNil) + typed[NonCCLazy](fD) + assertEquals(a, fD.prev) + assertEquals(c, fD.next) + } + + @Test + def testShapelessTagged: Unit = { + import ShapelessTaggedAux._ + + val lgen = LabelledGeneric[Dummy] + val s = s"${lgen from Record(i=tag[CustomTag](0))}" + assertEquals(s, "Dummy(0)") + } +} diff --git a/core/src/test/scala-2/shapeless/lenses.scala b/core/src/test/scala-2/shapeless/lenses.scala new file mode 100644 index 000000000..074f95e83 --- /dev/null +++ b/core/src/test/scala-2/shapeless/lenses.scala @@ -0,0 +1,39 @@ +package shapeless + +import org.junit.Test +import org.junit.Assert._ + +import lens._, nat._, record._, syntax.singleton._, tag.@@, test._, testutil._ + +class OpticTestsScala2 { + + @Test + def testLazyUnapply: Unit = { + val g = optic[BGraph[Int]] + val l = g.left + val rl = g.right.left + val rll = rl ~ l + val rlg = rl ~ g + val rrlv = g.right.right.left.value + val rrrv = g.right.right.right.value + val rrlvrrrv = rrlv ~ rrrv + val rrrlv = g.right.right.right.left.value + val rrrrlv = g.right.right.right.right.left.value + val looped = rrrlv ~ rrrrlv + + val rll(a, b) = new BNode(BTerm(1), new BNode(BTerm(2), BTerm(3))) + assertEquals(BTerm(2), a) + assertEquals(BTerm(1), b) + + lazy val g0 @ rll(x: BTerm[Int], y: BTerm[Int]) = new BNode(BTerm(1), new BNode(BTerm(2), new BNode(x, y))) + val rrlvrrrv(x1, y1) = g0 + assertEquals(2, x1) + assertEquals(1, y1) + + lazy val rlg(z: BTerm[Int], g1: BGraph[Int]) = new BNode(BTerm(1), new BNode(BTerm(2), new BNode(z, g1))) + + val looped(x2, y2) = g1 + assertEquals(1, x2) + assertEquals(2, y2) + } +} diff --git a/core/src/test/scala-3/shapeless/generic.scala b/core/src/test/scala-3/shapeless/generic.scala new file mode 100644 index 000000000..e148618bd --- /dev/null +++ b/core/src/test/scala-3/shapeless/generic.scala @@ -0,0 +1,6 @@ +package shapeless + +package GenericTestsAux { + + type TapRepr[A] = ConstTap[A] :+: InTap[A, Nothing] :+: OutTap[A, Any] :+: PipeTap[A, Any] :+: CNil +} diff --git a/core/src/test/scala-3/shapeless/hlist.scala b/core/src/test/scala-3/shapeless/hlist.scala new file mode 100644 index 000000000..3855be24a --- /dev/null +++ b/core/src/test/scala-3/shapeless/hlist.scala @@ -0,0 +1,13 @@ +package shapeless + +import scala.reflect.ClassTag + +trait HListTestsScalaCompat { this: HListTests => + + type PWS = Fruit + + given ClassTag[Nothing] = ClassTag.Nothing + + type IntStringDoubleBound >: String & (Int & Double) <: String | (Int | Double) + type AnyOrMatchable = Matchable +} diff --git a/core/src/test/scala/shapeless/annotation.scala b/core/src/test/scala/shapeless/annotation.scala index e43e1ccf3..3595d5250 100644 --- a/core/src/test/scala/shapeless/annotation.scala +++ b/core/src/test/scala/shapeless/annotation.scala @@ -116,8 +116,8 @@ class AnnotationTests { @Test def invalidAnnotation: Unit = { - illTyped(" Annotation[Other, Dummy] ", "could not find implicit value for parameter annotation: .*") - illTyped(" Annotation[Dummy, CC] ", "could not find implicit value for parameter annotation: .*") + illTyped(" Annotation[Other, Dummy] ") + illTyped(" Annotation[Dummy, CC] ") } @Test @@ -159,9 +159,9 @@ class AnnotationTests { @Test def invalidAnnotations: Unit = { - illTyped(" Annotations[Dummy, CC] ", "could not find implicit value for parameter annotations: .*") - illTyped(" Annotations[Dummy, Base] ", "could not find implicit value for parameter annotations: .*") - illTyped(" Annotations[Second, Dummy] ", "could not find implicit value for parameter annotations: .*") + illTyped(" Annotations[Dummy, CC] ") + illTyped(" Annotations[Dummy, Base] ") + illTyped(" Annotations[Second, Dummy] ") } @Test @@ -191,9 +191,9 @@ class AnnotationTests { @Test def invalidTypeAnnotations: Unit = { - illTyped(" TypeAnnotations[Dummy, CC2] ", "could not find implicit value for parameter annotations: .*") - illTyped(" TypeAnnotations[Dummy, Base] ", "could not find implicit value for parameter annotations: .*") - illTyped(" TypeAnnotations[Second, Dummy] ", "could not find implicit value for parameter annotations: .*") + illTyped(" TypeAnnotations[Dummy, CC2] ") + illTyped(" TypeAnnotations[Dummy, Base] ") + illTyped(" TypeAnnotations[Second, Dummy] ") } @Test @@ -208,9 +208,6 @@ class AnnotationTests { @Test def allTypeAnnotations: Unit = { - val st = AllTypeAnnotations[Base2].apply() // sealed trait - typed[(First :: HNil) :: (Second :: Third :: HNil) :: HNil](st) - val cc = AllTypeAnnotations[CC4].apply() // case class typed[(First :: HNil) :: HNil :: (Second :: Third :: HNil) :: HNil](cc) assert(cc == (First() :: HNil) :: HNil :: (Second(2, "b") :: Third('c') :: HNil) :: HNil) diff --git a/core/src/test/scala/shapeless/constraints.scala b/core/src/test/scala/shapeless/constraints.scala index 3e76640e5..762cf748d 100644 --- a/core/src/test/scala/shapeless/constraints.scala +++ b/core/src/test/scala/shapeless/constraints.scala @@ -390,15 +390,19 @@ class NotContainsConstraintTests { @Test def testGeneric: Unit ={ - notContains(Box2(1, 1), "1") - notContains(Box3(Pear, Pear, 1), Apple) + val b1 = Box2(1, 1) + notContains(b1, "1") + val b2 = Box3(Pear, Pear, 1) + notContains(b2, Apple) illTyped(""" - notContains(Box2(1, 1), 1) + val b3 = Box2(1, 1) + notContains(b3, 1) """) illTyped(""" - notContains(Box3(2, 1, Pear), Pear) + val b3 = Box3(2, 1, Pear) + notContains(b4, Pear) """) } } @@ -467,19 +471,24 @@ class IsDistinctConstraintTests { @Test def testGeneric: Unit ={ - isDistinct(Diff(1, 4.0)) - isDistinct(Diff(Pear, Apple)) + val d1 = Diff(1, 4.0) + isDistinct(d1) + val d2 = Diff(Pear, Apple) + isDistinct(d2) illTyped(""" - isDistinct(Same(1, 1)) + val d3 = Same(1, 1) + isDistinct(d3) """) illTyped(""" - isDistinct(Same(Apple, Pear)) + val d4 = Same(Apple, Pear) + isDistinct(d4) """) illTyped(""" - isDistinct(Diff("1", "2")) + val d5 = Diff("1", "2") + isDistinct(d5) """) } } \ No newline at end of file diff --git a/core/src/test/scala/shapeless/conversions.scala b/core/src/test/scala/shapeless/conversions.scala index a847b9b6b..dc18e5f85 100644 --- a/core/src/test/scala/shapeless/conversions.scala +++ b/core/src/test/scala/shapeless/conversions.scala @@ -86,19 +86,6 @@ class ConversionTests { def foo[F, L <: HList, R](f : F, l : L)(implicit fntp: FnToProduct.Aux[F, L => R]) = fntp(f)(l) val s2 = foo(sum, 2 :: 3 :: HNil) val ab2 = foo(ab, a :: HNil) - - class HListSyntax[A <: HList, F <: AnyRef](a: A) { - def applied[U](f: F)(implicit cftp: FnToProduct.Aux[f.type, A => U]): U = cftp(f)(a) - } - - implicit def mkSyntax[A <: HList, F <: AnyRef](a: A) - (implicit ffp: FnFromProduct.Aux[A => Any, F]): HListSyntax[A, F] = - new HListSyntax[A, F](a) - - val res = (2 :: "a" :: 1.3 :: HNil) applied ((i, s, d) => (s * i, d * i)) // Function argument types inferred - - assert((res: (String, Double)) == ("aa", 2.6)) - } @Test @@ -106,9 +93,9 @@ class ConversionTests { case class Foo(a : Int, b : String, c : Double) val f1 = Foo(23, "foo", 2.3) - val t1 = Foo.unapply(f1).get + val t1 = (23, "foo", 2.3) val hf = t1.productElements - val f2 = Foo.tupled(hf.tupled) + val f2 = (Foo.apply _).tupled(hf.tupled) assertEquals(f1, f2) } } diff --git a/core/src/test/scala/shapeless/default.scala b/core/src/test/scala/shapeless/default.scala index d88cd4387..5514fbf11 100644 --- a/core/src/test/scala/shapeless/default.scala +++ b/core/src/test/scala/shapeless/default.scala @@ -90,13 +90,13 @@ class DefaultTests { @Test def invalid: Unit = { - illTyped(" Default[Base] ", "could not find implicit value for parameter default: .*") + illTyped(" Default[Base] ") - illTyped(" Default[Dummy] ", "could not find implicit value for parameter default: .*") + illTyped(" Default[Dummy] ") - illTyped(" Default[Any] ", "could not find implicit value for parameter default: .*") - illTyped(" Default[AnyRef] ", "could not find implicit value for parameter default: .*") - illTyped(" Default[Array[Int]] ", "could not find implicit value for parameter default: .*") + illTyped(" Default[Any] ") + illTyped(" Default[AnyRef] ") + illTyped(" Default[Array[Int]] ") } @Test @@ -119,13 +119,13 @@ class DefaultTests { @Test def invalidAsRecord: Unit = { - illTyped(" Default.AsRecord[Base] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsRecord[Base] ") - illTyped(" Default.AsRecord[Dummy] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsRecord[Dummy] ") - illTyped(" Default.AsRecord[Any] ", "could not find implicit value for parameter default: .*") - illTyped(" Default.AsRecord[AnyRef] ", "could not find implicit value for parameter default: .*") - illTyped(" Default.AsRecord[Array[Int]] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsRecord[Any] ") + illTyped(" Default.AsRecord[AnyRef] ") + illTyped(" Default.AsRecord[Array[Int]] ") } @Test @@ -158,13 +158,13 @@ class DefaultTests { @Test def invalidAsOptions: Unit = { - illTyped(" Default.AsOptions[Base] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsOptions[Base] ") - illTyped(" Default.AsOptions[Dummy] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsOptions[Dummy] ") - illTyped(" Default.AsOptions[Any] ", "could not find implicit value for parameter default: .*") - illTyped(" Default.AsOptions[AnyRef] ", "could not find implicit value for parameter default: .*") - illTyped(" Default.AsOptions[Array[Int]] ", "could not find implicit value for parameter default: .*") + illTyped(" Default.AsOptions[Any] ") + illTyped(" Default.AsOptions[AnyRef] ") + illTyped(" Default.AsOptions[Array[Int]] ") } @Test diff --git a/core/src/test/scala/shapeless/generic.scala b/core/src/test/scala/shapeless/generic.scala index 7d29b2396..7a3d76017 100644 --- a/core/src/test/scala/shapeless/generic.scala +++ b/core/src/test/scala/shapeless/generic.scala @@ -94,25 +94,6 @@ package GenericTestsAux { at[T](t => gen.from(gen.to(t).map(inc))) } - sealed trait AbstractNonCC - class NonCCA(val i: Int, val s: String) extends AbstractNonCC - class NonCCB(val b: Boolean, val d: Double) extends AbstractNonCC - class NonCCWithVars(var c: Char, var l: Long) extends AbstractNonCC - class NonCCWithVal(val n: Int) extends AbstractNonCC { - val isEven: Boolean = n % 2 == 0 - } - - class NonCCWithCompanion private (val i: Int, val s: String) - object NonCCWithCompanion { - def apply(i: Int, s: String) = new NonCCWithCompanion(i, s) - def unapply(s: NonCCWithCompanion): Option[(Int, String)] = Some((s.i, s.s)) - } - - class NonCCLazy(prev0: => NonCCLazy, next0: => NonCCLazy) { - lazy val prev = prev0 - lazy val next = next0 - } - sealed trait Xor[+A, +B] case class Left[+LA](a: LA) extends Xor[LA, Nothing] case class Right[+RB](b: RB) extends Xor[Nothing, RB] @@ -120,27 +101,14 @@ package GenericTestsAux { sealed trait Base[BA, BB] case class Swap[SA, SB](a: SA, b: SB) extends Base[SB, SA] - sealed trait Overlapping - sealed trait OA extends Overlapping - case class OAC(s: String) extends OA - sealed trait OB extends Overlapping - case class OBC(s: String) extends OB - case class OAB(i: Int) extends OA with OB - object SemiAuto { case object CObj object NonCObj } case class CCOrdered[A: Ordering](value: A) - class CCLikeOrdered[A: Ordering](val value: A) case class CCDegen(i: Int)() - class CCLikeDegen(val i: Int)() - - class Squared(x: Long) { - val x2 = x * x - } sealed trait Tap[A] final case class ConstTap[A](a: A) extends Tap[A] @@ -155,7 +123,7 @@ class GenericTests { import test._ type ABP = Apple :+: Banana :+: Pear :+: CNil - type APBO = Apple :+: Banana :+: Orange :+: Pear :+: CNil + type APBO = Apple :+: Pear :+: Banana :+: Orange :+: CNil type ABC = A.type :+: B.type :+: C.type :+: CNil @@ -298,17 +266,6 @@ class GenericTests { typed[AbstractSingle](s1) } - @Test - def testOverlappingCoproducts: Unit = { - val gen = Generic[Overlapping] - val o: Overlapping = OAB(1) - val o0 = gen.to(o) - typed[OAB :+: OAC :+: OBC :+: CNil](o0) - - val o1 = gen.from(o0) - typed[Overlapping](o1) - } - @Test def testCaseObjects: Unit = { val a: Enum = A @@ -372,7 +329,7 @@ class GenericTests { @Test def testParametrized: Unit = { val t: Tree[Int] = Node(Node(Leaf(23), Leaf(13)), Leaf(11)) - type NI = Leaf[Int] :+: Node[Int] :+: CNil + type NI = Node[Int] :+: Leaf[Int] :+: CNil val gen = Generic[Tree[Int]] @@ -453,138 +410,15 @@ class GenericTests { assertTypedEquals[IB](Inl(s), s0) } - @Test - def testAbstractNonCC: Unit = { - val ncca = new NonCCA(23, "foo") - val nccb = new NonCCB(true, 2.0) - val nccc = new NonCCWithVars('c', 42) - val nccd = new NonCCWithVal(313) - val ancc: AbstractNonCC = ncca - - val genA = Generic[NonCCA] - val genB = Generic[NonCCB] - val genC = Generic[NonCCWithVars] - val genD = Generic[NonCCWithVal] - val genAbs = Generic[AbstractNonCC] - - val rA = genA.to(ncca) - assertTypedEquals[Int :: String :: HNil](23 :: "foo" :: HNil, rA) - - val rB = genB.to(nccb) - assertTypedEquals[Boolean :: Double :: HNil](true :: 2.0 :: HNil, rB) - - val rC = genC.to(nccc) - assertTypedEquals[Char :: Long :: HNil]('c' :: 42L :: HNil, rC) - - val rD = genD.to(nccd) - assertTypedEquals[Int :: HNil](313 :: HNil, rD) - - val rAbs = genAbs.to(ancc) - assertTypedEquals[NonCCA :+: NonCCB :+: NonCCWithVal :+: NonCCWithVars :+: CNil](Inl(ncca), rAbs) - - val fA = genA.from(13 :: "bar" :: HNil) - typed[NonCCA](fA) - assertEquals(13, fA.i) - assertEquals("bar", fA.s) - - val fB = genB.from(false :: 3.0 :: HNil) - typed[NonCCB](fB) - assertEquals(false, fB.b) - assertEquals(3.0, fB.d, Double.MinPositiveValue) - - val fC = genC.from('k' :: 313L :: HNil) - typed[NonCCWithVars](fC) - assertEquals('k', fC.c) - assertEquals(313L, fC.l) - - val fD = genD.from(99 :: HNil) - typed[NonCCWithVal](fD) - assertEquals(99, fD.n) - - val fAbs = genAbs.from(Inr(Inl(nccb))) - typed[AbstractNonCC](fAbs) - assertTrue(fAbs.isInstanceOf[NonCCB]) - assertEquals(true, fAbs.asInstanceOf[NonCCB].b) - assertEquals(2.0, fAbs.asInstanceOf[NonCCB].d, Double.MinPositiveValue) - } - - @Test - def testNonCCWithCompanion: Unit = { - val nccc = NonCCWithCompanion(23, "foo") - - val gen = Generic[NonCCWithCompanion] - - val r = gen.to(nccc) - assertTypedEquals[Int :: String :: HNil](23 :: "foo" :: HNil, r) - - val f = gen.from(13 :: "bar" :: HNil) - typed[NonCCWithCompanion](f) - assertEquals(13, f.i) - assertEquals("bar", f.s) - } - - @Test - def testNonCCLazy: Unit = { - lazy val (a: NonCCLazy, b: NonCCLazy, c: NonCCLazy) = - (new NonCCLazy(c, b), new NonCCLazy(a, c), new NonCCLazy(b, a)) - - val gen = Generic[NonCCLazy] - - val rB = gen.to(b) - assertTypedEquals[NonCCLazy :: NonCCLazy :: HNil](a :: c :: HNil, rB) - - val fD = gen.from(a :: c :: HNil) - typed[NonCCLazy](fD) - assertEquals(a, fD.prev) - assertEquals(c, fD.next) - } - - trait Parent { - case class Nested(i: Int, s: String) - - sealed abstract class Foo extends Product with Serializable - - case object A extends Foo - case object B extends Foo - case class C() extends Foo - } - - trait Child extends Parent { - val gen = Generic[Nested] - val adtGen = Generic[Foo] - } - - object O extends Child - - @Test - def testNestedInherited: Unit = { - val n0 = O.Nested(23, "foo") - val repr = O.gen.to(n0) - typed[Int :: String :: HNil](repr) - val n1 = O.gen.from(repr) - typed[O.Nested](n1) - assertEquals(n0, n1) - - { - val foo0 = O.B - val repr = O.adtGen.to(foo0) - typed[O.A.type :+: O.B.type :+: O.C :+: CNil](repr) - } - - { - val foo0 = O.C() - val repr = O.adtGen.to(foo0) - typed[O.A.type :+: O.B.type :+: O.C :+: CNil](repr) - } - } + def use(@scala.annotation.unused v: Any): Unit = () @Test def testIsTuple: Unit = { import record._ import union._ - IsTuple[Unit] - IsTuple[(Int, String)] + use(IsTuple[Unit]) + use(IsTuple[(Int, String)]) illTyped(" IsTuple[HNil] ") illTyped(" IsTuple[Int :: String :: HNil] ") @@ -606,13 +440,13 @@ class GenericTests { import record._ import union._ - HasProductGeneric[Single] - HasProductGeneric[Person] - HasProductGeneric[Unit] - HasProductGeneric[(Int, String)] - HasProductGeneric[A.type] - HasProductGeneric[Single] - HasProductGeneric[Person] + use(HasProductGeneric[Single]) + use(HasProductGeneric[Person]) + use(HasProductGeneric[Unit]) + use(HasProductGeneric[(Int, String)]) + use(HasProductGeneric[A.type]) + use(HasProductGeneric[Single]) + use(HasProductGeneric[Person]) illTyped(" HasProductGeneric[HNil] ") illTyped(" HasProductGeneric[Int :: String :: HNil] ") @@ -631,7 +465,7 @@ class GenericTests { import record._ import union._ - HasCoproductGeneric[Fruit] + use(HasCoproductGeneric[Fruit]) illTyped(" HasCoproductGeneric[Unit] ") illTyped(" HasCoproductGeneric[(Int, String)] ") @@ -673,10 +507,10 @@ class GenericTests { @Test def testNestedCaseObjects: Unit = { - Generic[Green.type] - Generic[Color.Red.type] - LabelledGeneric[Green.type] - LabelledGeneric[Color.Red.type] + use(Generic[Green.type]) + use(Generic[Color.Red.type]) + use(LabelledGeneric[Green.type]) + use(LabelledGeneric[Color.Red.type]) } sealed trait Base1 @@ -699,7 +533,7 @@ class GenericTests { @Test def testCaseObjectsAndLazy: Unit = { - TC[Base1] + use(TC[Base1]) } @Test @@ -767,62 +601,12 @@ class GenericTests { illTyped("Generic[T]") } - @Test - def testPathViaSubPrefix: Unit = { - class Outer { - class Inner { - sealed trait T - } - - val inner = new Inner - case class C(i: Int) extends inner.T - case object O extends inner.T - } - - val outer = new Outer - type Repr = outer.C :+: outer.O.type :+: CNil - val gen = Generic[outer.inner.T] - val c = outer.C(42) - val injC: Repr = Inl(c) - val injO: Repr = Inr(Inl(outer.O)) - - assertTypedEquals[Repr](injC, gen.to(c)) - assertTypedEquals[outer.inner.T](c, gen.from(injC)) - assertTypedEquals[Repr](injO, gen.to(outer.O)) - assertTypedEquals[outer.inner.T](outer.O, gen.from(injO)) - } - - @Test - def testGenericImplicitParams: Unit = { - type Repr = Int :: HNil - val gen = Generic[CCOrdered[Int]] - val cc = CCOrdered(42) - val rep = 42 :: HNil - - assertTypedEquals[CCOrdered[Int]](gen.from(rep), cc) - assertTypedEquals[Repr](gen.to(cc), rep) - illTyped("Generic[CCLikeOrdered[Int]]") - } - - @Test - def testGenericDegenerate: Unit = { - type Repr = Int :: HNil - val gen = Generic[CCDegen] - val cc = CCDegen(313)() - val rep = 313 :: HNil - - assertTypedEquals[CCDegen](gen.from(rep), cc) - assertTypedEquals[Repr](gen.to(cc), rep) - illTyped("Generic[CCLikeDegen]") - } - @Test def testCtorFieldsMismatch: Unit = { illTyped("Generic[Squared]") } def testCoproductWithFreeTypeParams: Unit = { - type Repr[A] = ConstTap[A] :+: InTap[A, _] :+: OutTap[A, _] :+: PipeTap[A, _] :+: CNil val gen = Generic[Tap[String]] val const = ConstTap("simple") @@ -830,7 +614,7 @@ class GenericTests { val out = OutTap[String, Option[Char]](_.headOption) val pipe = PipeTap[String, Array[Byte]](new String(_), _.getBytes) - val testData = List[(Tap[String], Repr[String])]( + val testData = List[(Tap[String], TapRepr[String])]( const -> Inl(const), in -> Inr(Inl(in)), out -> Inr(Inr(Inl(out))), @@ -929,117 +713,6 @@ package GenericTestsAux2 { */ } -object MixedCCNonCCNested { - // Block local - { - object T1{ - sealed abstract class Tree - final case class Node(left: Tree, right: Tree, v: Int) extends Tree - case object Leaf extends Tree - } - - Generic[T1.Tree] - import T1._ - Generic[Tree] - - sealed trait A - sealed case class B(i: Int, s: String) extends A - case object C extends A - sealed trait D extends A - final case class E(a: Double, b: Option[Float]) extends D - case object F extends D - sealed abstract class Foo extends D - case object Baz extends Foo - final class Bar extends Foo - final class Baz(val i1: Int, val s1: String) extends Foo - - Generic[A] - Generic[B] - Generic[C.type] - Generic[D] - Generic[E] - Generic[F.type] - Generic[Foo] - Generic[Baz.type] - Generic[Bar] - Generic[Baz] - } - - def methodLocal: Unit = { - object T1{ - sealed abstract class Tree - final case class Node(left: Tree, right: Tree, v: Int) extends Tree - case object Leaf extends Tree - } - - Generic[T1.Tree] - import T1._ - Generic[Tree] - - sealed trait A - sealed case class B(i: Int, s: String) extends A - case object C extends A - sealed trait D extends A - final case class E(a: Double, b: Option[Float]) extends D - case object F extends D - sealed abstract class Foo extends D - case object Baz extends Foo - final class Bar extends Foo - final class Baz(val i1: Int, val s1: String) extends Foo - - Generic[A] - Generic[B] - Generic[C.type] - Generic[D] - Generic[E] - Generic[F.type] - Generic[Foo] - Generic[Baz.type] - Generic[Bar] - Generic[Baz] - } - - // Top level - object T1{ - sealed abstract class Tree - final case class Node(left: Tree, right: Tree, v: Int) extends Tree - case object Leaf extends Tree - } - - Generic[T1.Tree] - import T1._ - Generic[Tree] - - sealed trait A - sealed case class B(i: Int, s: String) extends A - case object C extends A - sealed trait D extends A - final case class E(a: Double, b: Option[Float]) extends D - case object F extends D - sealed abstract class Foo extends D - case object Baz extends Foo - final class Bar extends Foo - final class Baz(val i1: Int, val s1: String) extends Foo - - Generic[A] - Generic[B] - Generic[C.type] - Generic[D] - Generic[E] - Generic[F.type] - Generic[Foo] - Generic[Baz.type] - Generic[Bar] - Generic[Baz] -} - -object EnumDefns0 { - sealed trait EnumVal - val BarA = new EnumVal { val name = "A" } - val BarB = new EnumVal { val name = "B" } - val BarC = new EnumVal { val name = "C" } -} - object EnumDefns1 { sealed trait EnumVal object BarA extends EnumVal { val name = "A" } @@ -1054,20 +727,6 @@ object EnumDefns2 { case object BarC extends EnumVal { val name = "C" } } -object EnumDefns3 { - sealed trait EnumVal - val BarA, BarB, BarC = new EnumVal {} -} - -object EnumDefns4 { - sealed trait EnumVal - object EnumVal { - val BarA = new EnumVal { val name = "A" } - val BarB = new EnumVal { val name = "B" } - val BarC = new EnumVal { val name = "C" } - } -} - object EnumDefns5 { sealed trait EnumVal object EnumVal { @@ -1086,28 +745,7 @@ object EnumDefns6 { } } -object EnumDefns7 { - sealed trait EnumVal - object EnumVal { - val BarA, BarB, BarC = new EnumVal {} - } -} - class TestEnum { - @Test - def testEnum0: Unit = { - import EnumDefns0._ - - val gen = Generic[EnumVal] - val a0 = gen.to(BarA) - assert(a0 == Inl(BarA)) - - val b0 = gen.to(BarB) - assert(b0 == Inr(Inl(BarB))) - - val c0 = gen.to(BarC) - assert(c0 == Inr(Inr(Inl(BarC)))) - } @Test def testEnum1: Unit = { @@ -1139,37 +777,6 @@ class TestEnum { assert(c0 == Inr(Inr(Inl(BarC)))) } - @Test - def testEnum3: Unit = { - import EnumDefns3._ - - val gen = Generic[EnumVal] - val a0 = gen.to(BarA) - assert(a0 == Inl(BarA)) - - val b0 = gen.to(BarB) - assert(b0 == Inr(Inl(BarB))) - - val c0 = gen.to(BarC) - assert(c0 == Inr(Inr(Inl(BarC)))) - } - - @Test - def testEnum4: Unit = { - import EnumDefns4._ - import EnumVal._ - - val gen = Generic[EnumVal] - val a0 = gen.to(BarA) - assert(a0 == Inl(BarA)) - - val b0 = gen.to(BarB) - assert(b0 == Inr(Inl(BarB))) - - val c0 = gen.to(BarC) - assert(c0 == Inr(Inr(Inl(BarC)))) - } - @Test def testEnum5: Unit = { import EnumDefns5._ @@ -1201,22 +808,6 @@ class TestEnum { val c0 = gen.to(BarC) assert(c0 == Inr(Inr(Inl(BarC)))) } - - @Test - def testEnum7: Unit = { - import EnumDefns7._ - import EnumVal._ - - val gen = Generic[EnumVal] - val a0 = gen.to(BarA) - assert(a0 == Inl(BarA)) - - val b0 = gen.to(BarB) - assert(b0 == Inr(Inl(BarB))) - - val c0 = gen.to(BarC) - assert(c0 == Inr(Inr(Inl(BarC)))) - } } package TestPrefixes1 { @@ -1236,9 +827,6 @@ package TestPrefixes1 { Generic[Defs.CC] Generic[Defs.SumI] Generic[Defs.SumS] - - Generic[Defs.Sum] - Generic.materialize[Defs.Sum, Defs.SumI :+: Defs.SumS :+: CNil] } } @@ -1250,34 +838,6 @@ package TestSingletonMembers { } } -object PathVariantDefns { - sealed trait AtomBase { - sealed trait Atom - case class Zero(value: String) extends Atom - } - - trait Atom1 extends AtomBase { - case class One(value: String) extends Atom - } - - trait Atom2 extends AtomBase { - case class Two(value: String) extends Atom - } - - object Atoms01 extends AtomBase with Atom1 - object Atoms02 extends AtomBase with Atom2 -} - -object PathVariants { - import PathVariantDefns._ - - val gen1 = Generic[Atoms01.Atom] - implicitly[gen1.Repr =:= (Atoms01.One :+: Atoms01.Zero :+: CNil)] - - val gen2 = Generic[Atoms02.Atom] - implicitly[gen2.Repr =:= (Atoms02.Two :+: Atoms02.Zero :+: CNil)] -} - object PrivateCtorDefns { sealed trait PublicFamily case class PublicChild() extends PublicFamily @@ -1292,45 +852,6 @@ object PrivateCtor { """) } -object Thrift { - object TProduct { - def apply(a: Double, b: String): TProduct = new Immutable(a, b) - - def unapply(tp: TProduct): Option[Product2[Double, String]] = Some(tp) - - //class Immutable(val a: Double, val b: String) extends TProduct - - class Immutable( - val a: Double, - val b: String, - val _passthroughFields: scala.collection.immutable.Map[Short, Byte] - ) extends TProduct { - def this( - a: Double, - b: String - ) = this( - a, - b, - Map.empty - ) - } - } - - trait TProduct extends Product2[Double, String] { - def a: Double - def b: String - - def _1 = a - def _2 = b - - override def productPrefix: String = "TProduct" - - def canEqual(t: Any): Boolean = true - } - - Generic[TProduct.Immutable] -} - object HigherKinded { // https://github.com/milessabin/shapeless/issues/683 type Id[A] = A diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 611fe46f5..3862a2c70 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -22,7 +22,7 @@ import org.junit.Assert._ import test._ import testutil._ -class HListTests { +class HListTests extends HListsTestScalaCompat { import nat._ import poly._ import syntax.std.traversable._ @@ -58,8 +58,6 @@ class HListTests { case class Pear() extends Fruit case class Banana() extends Fruit - type PWS = Product with Serializable with Fruit - type YYYY = Any :: Any :: Any :: Any :: HNil type FF = Fruit :: Fruit :: HNil type AP = Apple :: Pear :: HNil @@ -577,7 +575,7 @@ class HListTests { val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[List] assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) // equalInferredTypes(m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) - assertTypedEquals[List[M2[_ >: Double with Int with String, _]]]( + assertTypedEquals[List[M2[IntStringDoubleBound, _]]]( m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) } @@ -632,7 +630,7 @@ class HListTests { val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[Array] assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) // equalInferredTypes(m2eim2esm2eim2eem2edArray, sizedM2eim2esm2eim2eem2ed.unsized) - typed[Array[M2[_ >: Double with Int with String, _]]](sizedM2eim2esm2eim2eem2ed.unsized) + typed[Array[M2[IntStringDoubleBound, _]]](sizedM2eim2esm2eim2eem2ed.unsized) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x: Any), sizedM2eim2esm2eim2eem2ed.unsized.map(x => x: Any)) } @@ -983,7 +981,7 @@ class HListTests { val m = mimsmimimd.to[Array] equalInferredTypes(mimsmimimdArray, m) - typed[Array[M[_ >: Int with String with Double]]](m) + typed[Array[M[IntStringDoubleBound]]](m) assertArrayEquals2(mimsmimimdArray, m) val mWithEx = mimsmimemd.to[Array] @@ -993,12 +991,12 @@ class HListTests { val m2 = m2im2sm2im2im2d.to[Array] equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2[_ >: Int with String with Double, Unit]]](m2) + typed[Array[M2[IntStringDoubleBound, Unit]]](m2) assertArrayEquals2(m2im2sm2im2im2dArray, m2) val m2e = m2eim2esm2eim2eem2ed.to[Array] // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2[_ >: Int with String with Double, _]]](m2e) + typed[Array[M2[IntStringDoubleBound, _]]](m2e) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) } @@ -1039,12 +1037,12 @@ class HListTests { val l1 = 1 :: "foo" :: 2 :: 3 :: HNil val stuff = l1.toArray - typed[Array[Any]](stuff) + typed[Array[AnyOrMatchable]](stuff) assertArrayEquals2(Array(1, "foo", 2, 3), stuff) val ssl = "foo" :: "bar" :: 1L :: HNil val ssla = ssl.toArray - typed[Array[Any]](ssla) + typed[Array[AnyOrMatchable]](ssla) assertArrayEquals2(Array("foo", "bar", 1L), ssla) val stuff2 = stuff.toHList[ISII] @@ -1072,7 +1070,7 @@ class HListTests { val m = mimsmimimd.toArray equalInferredTypes(mimsmimimdArray, m) - typed[Array[M[_ >: Int with String with Double]]](m) + typed[Array[M[IntStringDoubleBound]]](m) assertArrayEquals2(mimsmimimdArray, m) val mWithEx = mimsmimemd.toArray[M[_]] @@ -1082,12 +1080,12 @@ class HListTests { val m2 = m2im2sm2im2im2d.toArray equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2[_ >: Int with String with Double, Unit]]](m2) + typed[Array[M2[IntStringDoubleBound]]](m2) assertArrayEquals2(m2im2sm2im2im2dArray, m2) val m2e = m2eim2esm2eim2eem2ed.toArray // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2[_ >: Int with String with Double, _]]](m2e) + typed[Array[M2[IntStringDoubleBound, _]]](m2e) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) } diff --git a/core/src/test/scala/shapeless/labelledgeneric.scala b/core/src/test/scala/shapeless/labelledgeneric.scala index ada782068..3d0a5720f 100644 --- a/core/src/test/scala/shapeless/labelledgeneric.scala +++ b/core/src/test/scala/shapeless/labelledgeneric.scala @@ -321,7 +321,7 @@ class LabelledGenericTests { @Test def testCoproductBasics: Unit = { - type TreeUnion = ("Leaf" ->> Leaf) :+: ("Node" ->> Node) :+: CNil + type TreeUnion = ("Node" ->> Node) :+: ("Leaf" ->> Leaf) :+: CNil val gen = LabelledGeneric[Tree] @@ -330,94 +330,6 @@ class LabelledGenericTests { typed[TreeUnion](gt) } - @Test - def testAbstractNonCC: Unit = { - val ncca = new NonCCA(23, "foo") - val nccb = new NonCCB(true, 2.0) - val ancc: AbstractNonCC = ncca - - type NonCCARec = ("i" ->> Int) :: ("s" ->> String) :: HNil - type NonCCBRec = ("b" ->> Boolean) :: ("d" ->> Double) :: HNil - type AbsUnion = ("NonCCA" ->> NonCCA) :+: ("NonCCB" ->> NonCCB) :+: CNil - - val genA = LabelledGeneric[NonCCA] - val genB = LabelledGeneric[NonCCB] - val genAbs = LabelledGeneric[AbstractNonCC] - - val rA = genA.to(ncca) - assertTypedEquals[NonCCARec]("i" ->> 23 :: "s" ->> "foo" :: HNil, rA) - - val rB = genB.to(nccb) - assertTypedEquals[NonCCBRec]("b" ->> true :: "d" ->> 2.0 :: HNil, rB) - - val rAbs = genAbs.to(ancc) - val injA = Coproduct[AbsUnion]("NonCCA" ->> ncca) - assertTypedEquals[AbsUnion](injA, rAbs) - - val fA = genA.from("i" ->> 13 :: "s" ->> "bar" :: HNil) - typed[NonCCA](fA) - assertEquals(13, fA.i) - assertEquals("bar", fA.s) - - val fB = genB.from("b" ->> false :: "d" ->> 3.0 :: HNil) - typed[NonCCB](fB) - assertEquals(false, fB.b) - assertEquals(3.0, fB.d, Double.MinPositiveValue) - - val injB = Coproduct[AbsUnion]("NonCCB" ->> nccb) - val fAbs = genAbs.from(injB) - typed[AbstractNonCC](fAbs) - assertTrue(fAbs.isInstanceOf[NonCCB]) - assertEquals(true, fAbs.asInstanceOf[NonCCB].b) - assertEquals(2.0, fAbs.asInstanceOf[NonCCB].d, Double.MinPositiveValue) - } - - @Test - def testNonCCWithCompanion: Unit = { - val nccc = NonCCWithCompanion(23, "foo") - - val rec = ("i" ->> 23) :: ("s" ->> "foo") :: HNil - type NonCCRec = ("i" ->> Int) :: ("s" ->> String) :: HNil - - val gen = LabelledGeneric[NonCCWithCompanion] - - val r = gen.to(nccc) - assertTypedEquals[NonCCRec](rec, r) - - val f = gen.from("i" ->> 13 :: "s" ->> "bar" :: HNil) - typed[NonCCWithCompanion](f) - assertEquals(13, f.i) - assertEquals("bar", f.s) - } - - @Test - def testNonCCLazy: Unit = { - lazy val (a: NonCCLazy, b: NonCCLazy, c: NonCCLazy) = - (new NonCCLazy(c, b), new NonCCLazy(a, c), new NonCCLazy(b, a)) - - val rec = "prev" ->> a :: "next" ->> c :: HNil - type LazyRec = ("prev" ->> NonCCLazy) :: ("next" ->> NonCCLazy) :: HNil - - val gen = LabelledGeneric[NonCCLazy] - - val rB = gen.to(b) - assertTypedEquals[LazyRec](rec, rB) - - val fD = gen.from("prev" ->> a :: "next" ->> c :: HNil) - typed[NonCCLazy](fD) - assertEquals(a, fD.prev) - assertEquals(c, fD.next) - } - - @Test - def testShapelessTagged: Unit = { - import ShapelessTaggedAux._ - - val lgen = LabelledGeneric[Dummy] - val s = s"${lgen from Record(i=tag[CustomTag](0))}" - assertEquals(s, "Dummy(0)") - } - @Test def testScalazTagged: Unit = { diff --git a/core/src/test/scala/shapeless/lenses.scala b/core/src/test/scala/shapeless/lenses.scala index 20f6f1bf9..ea4346690 100644 --- a/core/src/test/scala/shapeless/lenses.scala +++ b/core/src/test/scala/shapeless/lenses.scala @@ -748,34 +748,4 @@ class OpticTests { assertTypedEquals[Int](2, y3) assertTypedEquals[Int](3, z3) } - - @Test - def testLazyUnapply: Unit = { - val g = optic[BGraph[Int]] - val l = g.left - val rl = g.right.left - val rll = rl ~ l - val rlg = rl ~ g - val rrlv = g.right.right.left.value - val rrrv = g.right.right.right.value - val rrlvrrrv = rrlv ~ rrrv - val rrrlv = g.right.right.right.left.value - val rrrrlv = g.right.right.right.right.left.value - val looped = rrrlv ~ rrrrlv - - val rll(a, b) = new BNode(BTerm(1), new BNode(BTerm(2), BTerm(3))) - assertEquals(BTerm(2), a) - assertEquals(BTerm(1), b) - - lazy val g0 @ rll(x: BTerm[Int], y: BTerm[Int]) = new BNode(BTerm(1), new BNode(BTerm(2), new BNode(x, y))) - val rrlvrrrv(x1, y1) = g0 - assertEquals(2, x1) - assertEquals(1, y1) - - lazy val rlg(z: BTerm[Int], g1: BGraph[Int]) = new BNode(BTerm(1), new BNode(BTerm(2), new BNode(z, g1))) - - val looped(x2, y2) = g1 - assertEquals(1, x2) - assertEquals(2, y2) - } } diff --git a/core/src/test/scala/shapeless/singletons.scala b/core/src/test/scala/shapeless/singletons.scala index e9e3259f3..c227e3c35 100644 --- a/core/src/test/scala/shapeless/singletons.scala +++ b/core/src/test/scala/shapeless/singletons.scala @@ -230,20 +230,20 @@ class SingletonTypesTests { def primitiveWiden: Unit = { { val w = Widen[2] - illTyped("w(3)", "type mismatch;.*") + illTyped("w(3)") val n = w(2) val n0: Int = n - illTyped("val n1: 2 = n", "type mismatch;.*") + illTyped("val n1: 2 = n") assertTypedEquals[Int](2, n) } { val w = Widen[true] - illTyped("w(false)", "type mismatch;.*") + illTyped("w(false)") val b = w(true) val b0: Boolean = b - illTyped("val b1: true = b", "type mismatch;.*") + illTyped("val b1: true = b") assertTypedEquals[Boolean](true, b) } @@ -278,10 +278,10 @@ class SingletonTypesTests { def aliasWiden: Unit = { type T = 2 val w = Widen[T] - illTyped("w(3)", "type mismatch;.*") + illTyped("w(3)") val n = w(2) val n0: Int = n - illTyped("val n1: 2 = n", "type mismatch;.*") + illTyped("val n1: 2 = n") assertTypedEquals[Int](2, n) } @@ -291,7 +291,7 @@ class SingletonTypesTests { @Test def singletonWiden: Unit = { - illTyped("Widen[A.type]", "could not find implicit value for parameter widen:.*") + illTyped("Widen[A.type]") } @Test diff --git a/examples/src/main/scala/shapeless/examples/enum.scala b/examples/src/main/scala-2/shapeless/enum.scala similarity index 92% rename from examples/src/main/scala/shapeless/examples/enum.scala rename to examples/src/main/scala-2/shapeless/enum.scala index 46bef5bf4..62134bef4 100644 --- a/examples/src/main/scala/shapeless/examples/enum.scala +++ b/examples/src/main/scala-2/shapeless/enum.scala @@ -68,7 +68,7 @@ object ShapelessEnumDemo extends App { case _ => false // compile time non-exhaustive match warning/error without this case } - assert(!isWeekend(Mon)) // + assert(!isWeekend(Mon)) // } // Infrastructure for the above. Original version due to Travis Brown, @@ -86,8 +86,8 @@ object Values { object MkValues { implicit def values[T, Repr <: Coproduct] - (implicit gen: Generic.Aux[T, Repr], v: Aux[T, Repr]): MkValues[T] = - new MkValues[T] { def values = v.values } + (implicit gen: Generic.Aux[T, Repr], v: Aux[T, Repr]): MkValues[T] = + new MkValues[T] { def values = v.values } trait Aux[T, Repr] { def values: List[T] @@ -98,7 +98,7 @@ object Values { new Aux[A, CNil] { def values = Nil } implicit def cconsAux[T, L <: T with Singleton, R <: Coproduct] - (implicit l: ValueOf[L], r: Aux[T, R]): Aux[T, L :+: R] = + (implicit l: ValueOf[L], r: Aux[T, R]): Aux[T, L :+: R] = new Aux[T, L :+: R] { def values = l.value :: r.values } } } From faa9ddf9c27f849e727cdbe02490e040657a8fc8 Mon Sep 17 00:00:00 2001 From: Katrix Date: Thu, 12 Aug 2021 15:27:06 +0200 Subject: [PATCH 30/32] More test fixes and such --- .jvmopts | 6 +- .../src/main/scala-3/shapeless/generic1.scala | 2 + .../main/scala-3/shapeless/singletons.scala | 3 + core/src/main/scala/shapeless/Testing3.scala | 83 ----------- core/src/main/scala/shapeless/generic1.scala | 2 - core/src/main/scala/shapeless/package.scala | 4 + .../{annotations.scala => annotation.scala} | 2 + core/src/test/scala-2/shapeless/generic.scala | 9 +- core/src/test/scala-2/shapeless/hlist.scala | 4 +- core/src/test/scala-2/shapeless/lenses.scala | 2 + core/src/test/scala-2/shapeless/refute.scala | 18 +++ core/src/test/scala-3/shapeless/generic.scala | 4 +- core/src/test/scala-3/shapeless/hlist.scala | 3 +- core/src/test/scala/shapeless/default.scala | 2 - core/src/test/scala/shapeless/generic.scala | 1 + core/src/test/scala/shapeless/hlist.scala | 18 +-- core/src/test/scala/shapeless/product.scala | 7 - core/src/test/scala/shapeless/refute.scala | 9 -- .../shapeless/{ => examples}/enum.scala | 0 .../scala-2/shapeless/examples/functor.scala | 133 ++++++++++++++++++ .../shapeless/examples/sexp.scala | 22 +-- .../main/scala-2/shapeless/examples/staging | 0 .../shapeless/examples/staging.scala | 2 +- .../scala/shapeless/examples/functor.scala | 133 ------------------ .../scala/shapeless/examples/monoids.scala | 2 +- .../scala/shapeless/examples/sorting.scala | 4 +- .../scala/shapeless/examples/unfold.scala | 2 +- 27 files changed, 206 insertions(+), 271 deletions(-) delete mode 100644 core/src/main/scala/shapeless/Testing3.scala rename core/src/test/scala-2/shapeless/{annotations.scala => annotation.scala} (97%) create mode 100644 core/src/test/scala-2/shapeless/refute.scala rename examples/src/main/scala-2/shapeless/{ => examples}/enum.scala (100%) create mode 100644 examples/src/main/scala-2/shapeless/examples/functor.scala rename examples/src/main/{scala => scala-2}/shapeless/examples/sexp.scala (91%) create mode 100644 examples/src/main/scala-2/shapeless/examples/staging rename examples/src/main/{scala => scala-2}/shapeless/examples/staging.scala (98%) diff --git a/.jvmopts b/.jvmopts index 9e2d10252..ddfbfaa5f 100644 --- a/.jvmopts +++ b/.jvmopts @@ -1,5 +1,5 @@ +-Xms4g +-Xmx12g +-Xss4m -Dsbt.color=always -Dsbt.supershell=true --Xms2g --Xmx3g --Xss4m diff --git a/core/src/main/scala-3/shapeless/generic1.scala b/core/src/main/scala-3/shapeless/generic1.scala index 834ec9022..ae32bc3cc 100644 --- a/core/src/main/scala-3/shapeless/generic1.scala +++ b/core/src/main/scala-3/shapeless/generic1.scala @@ -68,6 +68,8 @@ trait Generic1ScalaCompat extends Generic10{ trait Generic10ScalaCompat extends Generic10ScalaCompatLowPriority { + def apply[T[_], FR[_[_]]](implicit gen: Generic1[T, FR]): Generic1.Aux[T, FR, gen.R] = gen + given[FR[_[_]]](using frr: => FR[Const[HNil]#λ]): Generic1.Aux[Const[Unit]#λ, FR, Const[HNil]#λ] = new Generic1[Const[Unit]#λ, FR] { override type R[Z] = HNil diff --git a/core/src/main/scala-3/shapeless/singletons.scala b/core/src/main/scala-3/shapeless/singletons.scala index 74f9dcadf..ba549c200 100644 --- a/core/src/main/scala-3/shapeless/singletons.scala +++ b/core/src/main/scala-3/shapeless/singletons.scala @@ -25,10 +25,13 @@ trait WidenScalaCompat { object WidenScalaCompat { def widenImpl[T](using Quotes)(using tTpe: Type[T]): Expr[Widen[T]] = { + /* import quotes.reflect.* val widenType = TypeRepr.of[T].dealias.widenTermRefByName.widen.asType widenType.asInstanceOf[Type[_ >: T]] match { case '[out] => '{Widen.instance[T, out](t => t.asInstanceOf[out])} } + */ + '{???} } } diff --git a/core/src/main/scala/shapeless/Testing3.scala b/core/src/main/scala/shapeless/Testing3.scala deleted file mode 100644 index 8d03b3b7f..000000000 --- a/core/src/main/scala/shapeless/Testing3.scala +++ /dev/null @@ -1,83 +0,0 @@ -package shapeless - -import shapeless.nat._ - -import scala.deriving.Mirror -import scala.annotation.Annotation as saAnnotation -import shapeless.NotContainsConstraint.NotContains -import shapeless.labelled.->> -import shapeless.ops.coproduct.{ExtendRight, ExtendRightBy} -import shapeless.ops.hlist.{SelectAll, ToSized} -import shapeless.ops.nat.Sum -import shapeless.ops.record.{Extractor, Remover} -import shapeless.test.{illTyped, typed} - -@main def testing: Unit = { - type R = ("a" ->> Int) :: ("b" ->> String) :: HNil - /* - type RM1 = ("a" ->> Int) :: HNil - - val r = Remover[R, "a"] - val e1 = Extractor[R, RM1]( - Extractor.extract( - summon, - summon, - summon, - summon, - ) - ) - */ - - /* - val e2 = ExtendRightBy[Boolean :+: CNil, String :+: Boolean :+: CNil]( - ExtendRightBy.extendRightByCoproduct( - summon[ExtendRight[Boolean :+: CNil, String]], - summon - ) - ) - */ - - //SelectAll[R, ("a" ->> Int) :: HNil] - //SelectAll[("a" ->> Int) :: ("b" ->> Boolean) :: ("c" ->> String) :: HNil] - - /* - object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) - } - - - def range[R <: HList](a: Nat, b: Nat)(implicit - range: ops.nat.Range.Aux[a.N, b.N, R], - mapper: ops.hlist.Mapper[toInt.type, R] - ) = mapper(range()) - - (0, 1) ::(2, 3) ::(4, 'a') :: HNil == range(0, 5).group(2, 2, 'a' :: HNil) - (0, 1) ::(2, 3) ::(4, 'a') :: HNil == range(0, 5).group(2, 2, 'a' :: 'b' :: 'c' :: HNil) - */ - - /* - trait MyNat - case class Succ[P <: MyNat]() extends MyNat - class _0 extends MyNat - - trait MySum[A <: MyNat, B <: MyNat] extends Serializable { type Out <: MyNat } - object MySum { - def apply[A <: MyNat, B <: MyNat](implicit sum: MySum[A, B]): Aux[A, B, sum.Out] = sum - - type Aux[A <: MyNat, B <: MyNat, C <: MyNat] = MySum[A, B] { type Out = C } - - implicit def sum1[B <: MyNat]: Aux[_0, B, B] = new MySum[_0, B] { type Out = B } - implicit def sum2[A <: MyNat, B <: MyNat, C <: MyNat] - (implicit sum : MySum.Aux[A, Succ[B], C]): MySum.Aux[Succ[A], B, C] = new MySum[Succ[A], B] { type Out = C } - } - import MySum.{sum1, sum2} - - //implicitly[MySum.Aux[Succ[Succ[_0]], Succ[_0], Succ[Succ[Succ[_0]]]]] - - import Sum.{sum1, sum2} - scala.compiletime.ops.int - - implicitly[Sum.Aux[_2, _1, _3]] - //implicitly[Sum.Aux[_2, _3, _5]] - */ -} diff --git a/core/src/main/scala/shapeless/generic1.scala b/core/src/main/scala/shapeless/generic1.scala index aac01ac46..1169dc0de 100644 --- a/core/src/main/scala/shapeless/generic1.scala +++ b/core/src/main/scala/shapeless/generic1.scala @@ -30,8 +30,6 @@ trait Generic1[F[_], +FR[_[_]]] extends Serializable { object Generic1 extends Generic1ScalaCompat { type Aux[F[_], +FR[_[_]], R0[_]] = Generic1[F, FR] { type R[t] = R0[t] } - def apply[T[_], FR[_[_]]](implicit gen: Generic1[T, FR]): Generic1.Aux[T, FR, gen.R] = gen - def unsafeInstance[F[_], FR[_[_]], R0[_]](f: F[Any] => R0[Any], g: R0[Any] => F[Any])(implicit lazyFr: => FR[R0]): Aux[F, FR, R0] = { new Generic1[F, FR] { type R[t] = R0[t] diff --git a/core/src/main/scala/shapeless/package.scala b/core/src/main/scala/shapeless/package.scala index e8dbe9358..3b835d38c 100644 --- a/core/src/main/scala/shapeless/package.scala +++ b/core/src/main/scala/shapeless/package.scala @@ -92,6 +92,10 @@ package object shapeless extends ScalaVersionSpecifics { /** The SYB everywhere combinator */ type Everywhere[F <: Poly, T] = Case1[EverywhereAux[F], T] + /** + * WARNING: Exponential compile times. Using anything with depth of over 5 + * will cause compile times to go down the drain, and potentially OOM errors. + */ def everywhere[T, R](f: Poly)(t: T)( implicit cse: => Case1.Aux[EverywhereAux[f.type], T, R] ): R = cse(t) diff --git a/core/src/test/scala-2/shapeless/annotations.scala b/core/src/test/scala-2/shapeless/annotation.scala similarity index 97% rename from core/src/test/scala-2/shapeless/annotations.scala rename to core/src/test/scala-2/shapeless/annotation.scala index 118ec7b2e..f3ea33319 100644 --- a/core/src/test/scala-2/shapeless/annotations.scala +++ b/core/src/test/scala-2/shapeless/annotation.scala @@ -7,9 +7,11 @@ import shapeless.test.{illTyped, typed} class AnnotationTestsScala2 { import AnnotationTestsDefinitions._ + /* @Test def allTypeAnnotations: Unit = { val st = AllTypeAnnotations[Base2].apply() // sealed trait typed[(First :: HNil) :: (Second :: Third :: HNil) :: HNil](st) } + */ } diff --git a/core/src/test/scala-2/shapeless/generic.scala b/core/src/test/scala-2/shapeless/generic.scala index 29d562808..388c47b0e 100644 --- a/core/src/test/scala-2/shapeless/generic.scala +++ b/core/src/test/scala-2/shapeless/generic.scala @@ -58,7 +58,9 @@ package GenericTestsAux { class Squared(x: Long) { val x2 = x * x } - +} +object GenericTestsAuxScalaCompat { + import GenericTestsAux._ type TapRepr[A] = ConstTap[A] :+: InTap[A, _] :+: OutTap[A, _] :+: PipeTap[A, _] :+: CNil } @@ -454,8 +456,9 @@ package TestPrefixes1 { object DerivationsScala2 { import shapeless._ - Generic[Defs.Sum] - Generic.materialize[Defs.Sum, Defs.SumI :+: Defs.SumS :+: CNil] + //TODO: Should work. Stopped working as we stopped sorting the types + //Generic[Defs.Sum] + //Generic.materialize[Defs.Sum, Defs.SumI :+: Defs.SumS :+: CNil] } } diff --git a/core/src/test/scala-2/shapeless/hlist.scala b/core/src/test/scala-2/shapeless/hlist.scala index 14a6de825..6c21fa8d4 100644 --- a/core/src/test/scala-2/shapeless/hlist.scala +++ b/core/src/test/scala-2/shapeless/hlist.scala @@ -7,7 +7,9 @@ trait HListTestsScalaCompat { this: HListTests => type PWS = Product with Serializable with Fruit - type IntStringDoubleBound >: Double with Int with String + type MIntStringDoubleBound = M[_ >: Double with Int with String] + type M2IntStringDoubleBound[A] = M2[_ >: Double with Int with String, A] + type AnyOrMatchable = Any @Test diff --git a/core/src/test/scala-2/shapeless/lenses.scala b/core/src/test/scala-2/shapeless/lenses.scala index 074f95e83..a846fda74 100644 --- a/core/src/test/scala-2/shapeless/lenses.scala +++ b/core/src/test/scala-2/shapeless/lenses.scala @@ -5,6 +5,8 @@ import org.junit.Assert._ import lens._, nat._, record._, syntax.singleton._, tag.@@, test._, testutil._ +import lensTestDataTypes._ + class OpticTestsScala2 { @Test diff --git a/core/src/test/scala-2/shapeless/refute.scala b/core/src/test/scala-2/shapeless/refute.scala new file mode 100644 index 000000000..2fdf22921 --- /dev/null +++ b/core/src/test/scala-2/shapeless/refute.scala @@ -0,0 +1,18 @@ +package shapeless + +import org.junit.Test + +import test._ + +class RefuteTestsScala2 { + + import RefuteTests._ + + @Test + def increaseCodeCoverage: Unit = { + // Increases the code coverage, as the above tests cannot + Refute.Impl.amb1[PresentEvidence](presentEvidence) + Refute.Impl.amb2[PresentEvidence] + Refute.refute(new Refute.Impl[PresentEvidence]{}) + } +} diff --git a/core/src/test/scala-3/shapeless/generic.scala b/core/src/test/scala-3/shapeless/generic.scala index e148618bd..617b96951 100644 --- a/core/src/test/scala-3/shapeless/generic.scala +++ b/core/src/test/scala-3/shapeless/generic.scala @@ -1,6 +1,6 @@ package shapeless -package GenericTestsAux { - +package GenericTestsAux +object GenericTestsAuxScalaCompat { type TapRepr[A] = ConstTap[A] :+: InTap[A, Nothing] :+: OutTap[A, Any] :+: PipeTap[A, Any] :+: CNil } diff --git a/core/src/test/scala-3/shapeless/hlist.scala b/core/src/test/scala-3/shapeless/hlist.scala index 3855be24a..680664aae 100644 --- a/core/src/test/scala-3/shapeless/hlist.scala +++ b/core/src/test/scala-3/shapeless/hlist.scala @@ -8,6 +8,7 @@ trait HListTestsScalaCompat { this: HListTests => given ClassTag[Nothing] = ClassTag.Nothing - type IntStringDoubleBound >: String & (Int & Double) <: String | (Int | Double) + type MIntStringDoubleBound[A] = M[_ >: String & (Int & Double) <: String | (Int | Double), A] + type M2IntStringDoubleBound[A] = M2[_ >: String & (Int & Double) <: String | (Int | Double), A] type AnyOrMatchable = Matchable } diff --git a/core/src/test/scala/shapeless/default.scala b/core/src/test/scala/shapeless/default.scala index 5514fbf11..2f109d5af 100644 --- a/core/src/test/scala/shapeless/default.scala +++ b/core/src/test/scala/shapeless/default.scala @@ -132,7 +132,6 @@ class DefaultTests { def simpleAsOptions: Unit = { illTyped( " val default0: None.type :: Some[String] :: Some[Option[Boolean]] :: HNil = Default.AsOptions[CC].apply() ", - "type mismatch.*" ) val default = Default.AsOptions[CC].apply() @@ -146,7 +145,6 @@ class DefaultTests { def simpleFromPathAsOptions: Unit = { illTyped( " val default0: None.type :: Some[String] :: Some[Option[Boolean]] :: HNil = Default.AsOptions[definitions.CC].apply() ", - "type mismatch.*" ) val default = Default.AsOptions[definitions.CC].apply() diff --git a/core/src/test/scala/shapeless/generic.scala b/core/src/test/scala/shapeless/generic.scala index 7a3d76017..0f02b41ad 100644 --- a/core/src/test/scala/shapeless/generic.scala +++ b/core/src/test/scala/shapeless/generic.scala @@ -119,6 +119,7 @@ package GenericTestsAux { class GenericTests { import GenericTestsAux._ + import GenericTestsAuxScalaCompat._ import scala.collection.immutable.{ :: => Cons } import test._ diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 3862a2c70..3c183e00e 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -22,7 +22,7 @@ import org.junit.Assert._ import test._ import testutil._ -class HListTests extends HListsTestScalaCompat { +class HListTests extends HListTestsScalaCompat { import nat._ import poly._ import syntax.std.traversable._ @@ -575,7 +575,7 @@ class HListTests extends HListsTestScalaCompat { val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[List] assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) // equalInferredTypes(m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) - assertTypedEquals[List[M2[IntStringDoubleBound, _]]]( + assertTypedEquals[List[M2IntStringDoubleBound[_]]]( m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) } @@ -630,7 +630,7 @@ class HListTests extends HListsTestScalaCompat { val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[Array] assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) // equalInferredTypes(m2eim2esm2eim2eem2edArray, sizedM2eim2esm2eim2eem2ed.unsized) - typed[Array[M2[IntStringDoubleBound, _]]](sizedM2eim2esm2eim2eem2ed.unsized) + typed[Array[M2IntStringDoubleBound[_]]](sizedM2eim2esm2eim2eem2ed.unsized) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x: Any), sizedM2eim2esm2eim2eem2ed.unsized.map(x => x: Any)) } @@ -981,7 +981,7 @@ class HListTests extends HListsTestScalaCompat { val m = mimsmimimd.to[Array] equalInferredTypes(mimsmimimdArray, m) - typed[Array[M[IntStringDoubleBound]]](m) + typed[Array[MIntStringDoubleBound]](m) assertArrayEquals2(mimsmimimdArray, m) val mWithEx = mimsmimemd.to[Array] @@ -991,12 +991,12 @@ class HListTests extends HListsTestScalaCompat { val m2 = m2im2sm2im2im2d.to[Array] equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2[IntStringDoubleBound, Unit]]](m2) + typed[Array[M2IntStringDoubleBound[Unit]]](m2) assertArrayEquals2(m2im2sm2im2im2dArray, m2) val m2e = m2eim2esm2eim2eem2ed.to[Array] // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2[IntStringDoubleBound, _]]](m2e) + typed[Array[M2IntStringDoubleBound[_]]](m2e) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) } @@ -1070,7 +1070,7 @@ class HListTests extends HListsTestScalaCompat { val m = mimsmimimd.toArray equalInferredTypes(mimsmimimdArray, m) - typed[Array[M[IntStringDoubleBound]]](m) + typed[Array[MIntStringDoubleBound]](m) assertArrayEquals2(mimsmimimdArray, m) val mWithEx = mimsmimemd.toArray[M[_]] @@ -1080,12 +1080,12 @@ class HListTests extends HListsTestScalaCompat { val m2 = m2im2sm2im2im2d.toArray equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2[IntStringDoubleBound]]](m2) + typed[Array[M2IntStringDoubleBound[Unit]]](m2) assertArrayEquals2(m2im2sm2im2im2dArray, m2) val m2e = m2eim2esm2eim2eem2ed.toArray // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2[IntStringDoubleBound, _]]](m2e) + typed[Array[M2IntStringDoubleBound[_]]](m2e) assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) } diff --git a/core/src/test/scala/shapeless/product.scala b/core/src/test/scala/shapeless/product.scala index c9e669777..d9e4c3b77 100644 --- a/core/src/test/scala/shapeless/product.scala +++ b/core/src/test/scala/shapeless/product.scala @@ -285,13 +285,6 @@ class ProductTests { def testToMap: Unit = { import syntax.singleton._ - { - // FIXME: should work (needs changes in GenericMacros?) - // val m = Empty.toMap - // assertTypedEquals(Map.empty[Any, Nothing], m) - } - - val e = EmptyCC() { diff --git a/core/src/test/scala/shapeless/refute.scala b/core/src/test/scala/shapeless/refute.scala index d95f638d4..97871d970 100644 --- a/core/src/test/scala/shapeless/refute.scala +++ b/core/src/test/scala/shapeless/refute.scala @@ -32,13 +32,4 @@ class RefuteTests { def testInductivePresent: Unit = { the[InductiveEvidence] } - - @Test - def increaseCodeCoverage: Unit = { - // Increases the code coverage, as the above tests cannot - Refute.Impl.amb1[PresentEvidence](presentEvidence) - Refute.Impl.amb2[PresentEvidence] - Refute.refute(new Refute.Impl[PresentEvidence]{}) - } - } diff --git a/examples/src/main/scala-2/shapeless/enum.scala b/examples/src/main/scala-2/shapeless/examples/enum.scala similarity index 100% rename from examples/src/main/scala-2/shapeless/enum.scala rename to examples/src/main/scala-2/shapeless/examples/enum.scala diff --git a/examples/src/main/scala-2/shapeless/examples/functor.scala b/examples/src/main/scala-2/shapeless/examples/functor.scala new file mode 100644 index 000000000..ad96a6256 --- /dev/null +++ b/examples/src/main/scala-2/shapeless/examples/functor.scala @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless.examples + +import shapeless._ + +package FunctorDemoDefns { + case class Foo[T](t: T, ts: List[T]) + + sealed trait Tree[T] + case class Leaf[T](t: T) extends Tree[T] + case class Node[T](l: Tree[T], r: Tree[T]) extends Tree[T] +} + +object FunctorDemo extends App { + import FunctorDemoDefns._ + import functorSyntax._ + + def transform[F[_]: Functor, A, B](ft: F[A])(f: A => B): F[B] = ft.map(f) + + // Option has a Functor + val o = transform(Option("foo"))(_.length) + assert(o == Some(3)) + + // List has a Functor + val l = transform(List("foo", "wibble", "quux"))(_.length) + assert(l == List(3, 6, 4)) + + // Any case class has a Functor + val foo = Foo("Three", List("French", "Hens")) + + val f0 = transform(foo)(_.length) + val f1 = foo.map(_.length) // they also have Functor syntax ... + + val expectedFoo = Foo(5, List(6, 4)) + assert(f0 == expectedFoo) + assert(f1 == expectedFoo) + + // Any ADT has a Functor ... even with recursion + val tree = + Node( + Leaf("quux"), + Node( + Leaf("foo"), + Leaf("wibble") + ) + ) + + val t0 = transform(tree)(_.length) + val t1 = tree.map(_.length) // they also have Functor syntax ... + + val expectedTree = + Node( + Leaf(4), + Node( + Leaf(3), + Leaf(6) + ) + ) + assert(t0 == expectedTree) + assert(t1 == expectedTree) +} + +/** + * Illustrative subset of the Cats Functor type class + */ +trait Functor[F[_]] { + def map[A, B](fa: F[A])(f: A => B): F[B] +} + +object Functor extends Functor0 { + def apply[F[_]](implicit f: => Functor[F]): Functor[F] = f + + implicit val idFunctor: Functor[Id] = + new Functor[Id] { + def map[A, B](a: A)(f: A => B): B = f(a) + } + + // Induction step for products + implicit def hcons[F[_]](implicit ihc: IsHCons1[F, Functor, Functor]): Functor[F] = + new Functor[F] { + def map[A, B](fa: F[A])(f: A => B): F[B] = { + val (hd, tl) = ihc.unpack(fa) + ihc.pack((ihc.fh.map(hd)(f), ihc.ft.map(tl)(f))) + } + } + + implicit def constFunctor[T]: Functor[Const[T]#λ] = + new Functor[Const[T]#λ] { + def map[A, B](t: T)(f: A => B): T = t + } +} + +trait Functor0 extends Functor1 { + // Induction step for coproducts + implicit def ccons[F[_]](implicit icc: IsCCons1[F, Functor, Functor]): Functor[F] = + new Functor[F] { + def map[A, B](fa: F[A])(f: A => B): F[B] = + icc.pack(icc.unpack(fa).fold(hd => Left(icc.fh.map(hd)(f)), tl => Right(icc.ft.map(tl)(f)))) + } +} + +trait Functor1 { + implicit def generic[F[_]](implicit gen: Generic1[F, Functor]): Functor[F] = + new Functor[F] { + def map[A, B](fa: F[A])(f: A => B): F[B] = + gen.from(gen.fr.map(gen.to(fa))(f)) + } +} + +// Functor syntax +object functorSyntax { + implicit def apply[F[_]: Functor, A](fa: F[A]): FunctorOps[F, A] = + new FunctorOps[F, A](fa) + + class FunctorOps[F[_], A](fa: F[A])(implicit F: Functor[F]) { + def map[B](f: A => B): F[B] = F.map(fa)(f) + } +} diff --git a/examples/src/main/scala/shapeless/examples/sexp.scala b/examples/src/main/scala-2/shapeless/examples/sexp.scala similarity index 91% rename from examples/src/main/scala/shapeless/examples/sexp.scala rename to examples/src/main/scala-2/shapeless/examples/sexp.scala index 0fe5e54d5..6810823b1 100644 --- a/examples/src/main/scala/shapeless/examples/sexp.scala +++ b/examples/src/main/scala-2/shapeless/examples/sexp.scala @@ -102,11 +102,11 @@ package sexp.ast { case class DatabaseField(column: String) case class FieldTerm(text: String, field: DatabaseField, value: String) extends Term case class BoundedTerm( - text: String, - field: DatabaseField, - low: Option[String] = None, - high: Option[String] = None, - inclusive: Boolean = false) extends Term + text: String, + field: DatabaseField, + low: Option[String] = None, + high: Option[String] = None, + inclusive: Boolean = false) extends Term case class LikeTerm(term: FieldTerm, like: Option[Like]) extends Term { val text = like.map(_.text).getOrElse("") val field = term.field @@ -293,8 +293,8 @@ object SexpConvert { } implicit def deriveHCons[K <: String with Singleton, V, T <: HList]( - implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] - ): SexpConvert[FieldType[K, V] :: T] = new SexpConvert[FieldType[K, V] :: T] { + implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] + ): SexpConvert[FieldType[K, V] :: T] = new SexpConvert[FieldType[K, V] :: T] { def deser(s: Sexp): Option[FieldType[K, V] :: T] = s match { case SexpProp((label, car), cdr) if label == key.value => for { @@ -322,8 +322,8 @@ object SexpConvert { } implicit def deriveCCons[K <: String with Singleton, V, T <: Coproduct]( - implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] - ): SexpConvert[FieldType[K, V] :+: T] = new SexpConvert[FieldType[K, V] :+: T] { + implicit key: ValueOf[K], scv: => SexpConvert[V], sct: SexpConvert[T] + ): SexpConvert[FieldType[K, V] :+: T] = new SexpConvert[FieldType[K, V] :+: T] { def deser(s: Sexp): Option[FieldType[K, V] :+: T] = s match { case SexpCons(SexpAtom(impl), cdr) if impl == key.value => scv.deser(cdr).map(v => Inl(field[K](v))) @@ -341,8 +341,8 @@ object SexpConvert { } implicit def deriveInstance[F, G]( - implicit gen: LabelledGeneric.Aux[F, G], sg: => SexpConvert[G] - ): SexpConvert[F] = new SexpConvert[F] { + implicit gen: LabelledGeneric.Aux[F, G], sg: => SexpConvert[G] + ): SexpConvert[F] = new SexpConvert[F] { def deser(s: Sexp): Option[F] = sg.deser(s).map(gen.from) def ser(t: F): Sexp = sg.ser(gen.to(t)) } diff --git a/examples/src/main/scala-2/shapeless/examples/staging b/examples/src/main/scala-2/shapeless/examples/staging new file mode 100644 index 000000000..e69de29bb diff --git a/examples/src/main/scala/shapeless/examples/staging.scala b/examples/src/main/scala-2/shapeless/examples/staging.scala similarity index 98% rename from examples/src/main/scala/shapeless/examples/staging.scala rename to examples/src/main/scala-2/shapeless/examples/staging.scala index 9c3165856..f6e422b33 100644 --- a/examples/src/main/scala/shapeless/examples/staging.scala +++ b/examples/src/main/scala-2/shapeless/examples/staging.scala @@ -46,7 +46,7 @@ object StagedTypeClassExample extends App { shapeless.examples.StagedTypeClassExample.consumeTuple(t.asInstanceOf[($tpt1, $tpt2)]) """ - val fn = evalTree[((Any, Any)) => String](fnTree) + val fn = evalTree[((Any, Any)) => String](fnTree) fn(rawTuple) } diff --git a/examples/src/main/scala/shapeless/examples/functor.scala b/examples/src/main/scala/shapeless/examples/functor.scala index ad96a6256..e69de29bb 100644 --- a/examples/src/main/scala/shapeless/examples/functor.scala +++ b/examples/src/main/scala/shapeless/examples/functor.scala @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2015 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless.examples - -import shapeless._ - -package FunctorDemoDefns { - case class Foo[T](t: T, ts: List[T]) - - sealed trait Tree[T] - case class Leaf[T](t: T) extends Tree[T] - case class Node[T](l: Tree[T], r: Tree[T]) extends Tree[T] -} - -object FunctorDemo extends App { - import FunctorDemoDefns._ - import functorSyntax._ - - def transform[F[_]: Functor, A, B](ft: F[A])(f: A => B): F[B] = ft.map(f) - - // Option has a Functor - val o = transform(Option("foo"))(_.length) - assert(o == Some(3)) - - // List has a Functor - val l = transform(List("foo", "wibble", "quux"))(_.length) - assert(l == List(3, 6, 4)) - - // Any case class has a Functor - val foo = Foo("Three", List("French", "Hens")) - - val f0 = transform(foo)(_.length) - val f1 = foo.map(_.length) // they also have Functor syntax ... - - val expectedFoo = Foo(5, List(6, 4)) - assert(f0 == expectedFoo) - assert(f1 == expectedFoo) - - // Any ADT has a Functor ... even with recursion - val tree = - Node( - Leaf("quux"), - Node( - Leaf("foo"), - Leaf("wibble") - ) - ) - - val t0 = transform(tree)(_.length) - val t1 = tree.map(_.length) // they also have Functor syntax ... - - val expectedTree = - Node( - Leaf(4), - Node( - Leaf(3), - Leaf(6) - ) - ) - assert(t0 == expectedTree) - assert(t1 == expectedTree) -} - -/** - * Illustrative subset of the Cats Functor type class - */ -trait Functor[F[_]] { - def map[A, B](fa: F[A])(f: A => B): F[B] -} - -object Functor extends Functor0 { - def apply[F[_]](implicit f: => Functor[F]): Functor[F] = f - - implicit val idFunctor: Functor[Id] = - new Functor[Id] { - def map[A, B](a: A)(f: A => B): B = f(a) - } - - // Induction step for products - implicit def hcons[F[_]](implicit ihc: IsHCons1[F, Functor, Functor]): Functor[F] = - new Functor[F] { - def map[A, B](fa: F[A])(f: A => B): F[B] = { - val (hd, tl) = ihc.unpack(fa) - ihc.pack((ihc.fh.map(hd)(f), ihc.ft.map(tl)(f))) - } - } - - implicit def constFunctor[T]: Functor[Const[T]#λ] = - new Functor[Const[T]#λ] { - def map[A, B](t: T)(f: A => B): T = t - } -} - -trait Functor0 extends Functor1 { - // Induction step for coproducts - implicit def ccons[F[_]](implicit icc: IsCCons1[F, Functor, Functor]): Functor[F] = - new Functor[F] { - def map[A, B](fa: F[A])(f: A => B): F[B] = - icc.pack(icc.unpack(fa).fold(hd => Left(icc.fh.map(hd)(f)), tl => Right(icc.ft.map(tl)(f)))) - } -} - -trait Functor1 { - implicit def generic[F[_]](implicit gen: Generic1[F, Functor]): Functor[F] = - new Functor[F] { - def map[A, B](fa: F[A])(f: A => B): F[B] = - gen.from(gen.fr.map(gen.to(fa))(f)) - } -} - -// Functor syntax -object functorSyntax { - implicit def apply[F[_]: Functor, A](fa: F[A]): FunctorOps[F, A] = - new FunctorOps[F, A](fa) - - class FunctorOps[F[_], A](fa: F[A])(implicit F: Functor[F]) { - def map[B](f: A => B): F[B] = F.map(fa)(f) - } -} diff --git a/examples/src/main/scala/shapeless/examples/monoids.scala b/examples/src/main/scala/shapeless/examples/monoids.scala index c14235905..d0feb0e10 100644 --- a/examples/src/main/scala/shapeless/examples/monoids.scala +++ b/examples/src/main/scala/shapeless/examples/monoids.scala @@ -33,7 +33,7 @@ object MonoidExamples extends App { // Precompute and cache instance for Bar ... { - implicit val barInstance = Monoid[Bar] + implicit val barInstance: Monoid[Bar] = Monoid.deriveInstance[Bar, Boolean :: String :: Double :: HNil] val b = Bar(true, "foo", 1.0) |+| Bar(false, "bar", 3.0) assert(b == Bar(true, "foobar", 4.0)) diff --git a/examples/src/main/scala/shapeless/examples/sorting.scala b/examples/src/main/scala/shapeless/examples/sorting.scala index a4aef002f..ded15e36e 100644 --- a/examples/src/main/scala/shapeless/examples/sorting.scala +++ b/examples/src/main/scala/shapeless/examples/sorting.scala @@ -78,7 +78,7 @@ object Sorting { typed[_1](l1) typed[_2 :: _3 :: HNil](r1) - val (l2, r2) = selectLeast(_3 :: _1 :: _4 :: _0 :: _2 :: HNil) + val (l2, r2) = selectLeast(_3 :: _1 :: _4 :: shapeless.nat._0 :: _2 :: HNil) typed[_0](l2) typed[_3 :: _1 :: _4 :: _2 :: HNil](r2) @@ -110,7 +110,7 @@ object Sorting { /** * The punchline ... */ - val unsorted = _3 :: _1 :: _4 :: _0 :: _2 :: HNil + val unsorted = _3 :: _1 :: _4 :: shapeless.nat._0 :: _2 :: HNil typed[_3 :: _1 :: _4 :: _0 :: _2 :: HNil](unsorted) //acceptNonDecreasing(unsorted) // Does not compile! diff --git a/examples/src/main/scala/shapeless/examples/unfold.scala b/examples/src/main/scala/shapeless/examples/unfold.scala index 2694c69d5..f93673fd0 100644 --- a/examples/src/main/scala/shapeless/examples/unfold.scala +++ b/examples/src/main/scala/shapeless/examples/unfold.scala @@ -84,7 +84,7 @@ object UnfoldExamples extends App { println(l1) object unfoldFibs extends Poly1 { - implicit def case0: Case.Aux[_0, (_0, _1)] = at[_0](_ => (_0, _1)) + implicit def case0: Case.Aux[_0, (_0, _1)] = at[_0](_ => (shapeless.nat._0, _1)) implicit def case1: Case.Aux[_1, (_1, _2)] = at[_1](_ => (_1, _2)) implicit def caseN[N <: Nat, FN <: Nat, FSN <: Nat, FSSN <: Nat] (implicit From 0fbaddea992357ee5b7082d448bf7d646b6d4192 Mon Sep 17 00:00:00 2001 From: Katrix Date: Sun, 17 Jul 2022 17:00:34 +0200 Subject: [PATCH 31/32] Update Scala 3 version and fix errors --- build.sbt | 2 +- .../main/scala-3/shapeless/annotation.scala | 410 +-- .../main/scala-3/shapeless/coproduct.scala | 55 +- core/src/main/scala-3/shapeless/default.scala | 160 +- core/src/main/scala-3/shapeless/records.scala | 126 +- .../scala-3/shapeless/test/illTyped.scala | 138 +- .../src/main/scala-3/shapeless/typeable.scala | 667 ++-- core/src/main/scala-3/shapeless/unions.scala | 112 +- .../src/main/scala/shapeless/ops/tuples.scala | 2678 ++++++++--------- .../src/main/scala/shapeless/ops/zipper.scala | 666 ++-- 10 files changed, 2507 insertions(+), 2507 deletions(-) diff --git a/build.sbt b/build.sbt index bef17d08e..45f957e27 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject val Scala213 = "2.13.6" -val Scala3 = "3.0.3-RC1-bin-20210803-010f8de-NIGHTLY" +val Scala3 = "3.2.0-RC2" commonSettings noPublishSettings diff --git a/core/src/main/scala-3/shapeless/annotation.scala b/core/src/main/scala-3/shapeless/annotation.scala index ff1aa75a1..3b88e4383 100644 --- a/core/src/main/scala-3/shapeless/annotation.scala +++ b/core/src/main/scala-3/shapeless/annotation.scala @@ -1,205 +1,205 @@ -/* - * Copyright (c) 2015-9 Alexandre Archambault - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.compiletime.* -import scala.deriving.* -import scala.quoted.* - -trait AnnotationScalaCompat { - inline given[A, T]: Annotation[A, T] = ${AnnotationMacros.singleAnnotationForType[A, T]} - inline given[A, T]: Annotation[Option[A], T] = ${AnnotationMacros.singleOptAnnotationForType[A, T]} -} - -trait AnnotationsScalaCompat { - inline transparent given[A, T]: Annotations[A, T] = ${AnnotationMacros.allAnnotations[A, T]} -} - -trait TypeAnnotationsScalaCompat { - inline transparent given[A, T]: TypeAnnotations[A, T] = ${AnnotationMacros.allTypeAnnotations[A, T]} -} - -trait AllAnnotationsScalaCompat { - inline transparent given[T]: AllAnnotations[T] = ${AnnotationMacros.allAnnotationsForType[T]} -} - -trait AllTypeAnnotationsScalaCompat { - inline transparent given[T]: AllTypeAnnotations[T] = ${AnnotationMacros.allTypeAnnotationsForType[T]} -} - -object AnnotationMacros { - - private def errorIfInvalidAnnotation[A: Type](using quotes: Quotes): Unit = { - import quotes.reflect.* - - val tpe = TypeRepr.of[A] - val flags = tpe.typeSymbol.flags - if (flags.is(Flags.Abstract) || flags.is(Flags.Trait)) { - report.throwError(s"Bad annotation type ${tpe.show} is abstract") - } - } - - private def annotationsFromType(using quotes: Quotes)(enclosing: quotes.reflect.TypeRepr, tpe: quotes.reflect.TypeRepr): List[quotes.reflect.Term] = { - import quotes.reflect.* - tpe match { - case AnnotatedType(rest, term) => - term :: annotationsFromType(enclosing, rest) - //case ClassInfo(_, _, parents) => parents.flatMap(fromType(enclosing, _)) - case ref @ TypeRef(_, _) if ref.typeSymbol.isAliasType => annotationsFromType(enclosing, enclosing.memberType(ref.typeSymbol)) - case TypeBounds(low, hi) if low == hi => annotationsFromType(enclosing, low) - case _ => - Nil - } - } - - private def findAnnotation[A: Type](using quotes: Quotes)(tpe: quotes.reflect.TypeRepr, symbol: quotes.reflect.Symbol, typeAnnotations: Boolean = false): Option[Expr[A]] = { - import quotes.reflect.* - val annotationType = TypeRepr.of[A] - - val annotations = if (typeAnnotations) - annotationsFromType(tpe, tpe.memberType(symbol)) - else - symbol.annotations - - annotations.find(_.tpe <:< annotationType).map(_.asExprOf[A]) - } - - private def singleAnnotationForTypeCommon[A: Type, T: Type](using quotes: Quotes): Option[Expr[A]] = { - import quotes.reflect.* - errorIfInvalidAnnotation[A] - findAnnotation[A](TypeRepr.of[T], TypeRepr.of[T].typeSymbol) - } - - def singleAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[A, T]] = { - import quotes.reflect.* - singleAnnotationForTypeCommon[A, T] match { - case Some(expr) => '{Annotation.mkAnnotation($expr)} - case None => report.throwError(s"No ${Type.show[A]} annotation found on ${Type.show[T]}") - } - } - - def singleOptAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[Option[A], T]] = { - import quotes.reflect.* - singleAnnotationForTypeCommon[A, T] match { - case Some(expr) => '{Annotation.mkAnnotation(Some($expr))} - case None => '{Annotation.mkAnnotation(None)} - } - } - - private def productOrSumSymbols[T: Type](using quotes: Quotes): Seq[quotes.reflect.Symbol] = { - import quotes.reflect.* - val tpe = TypeRepr.of[T] - - tpe.classSymbol match { - case Some(clazzSym) if clazzSym.flags.is(Flags.Case) => - clazzSym.primaryConstructor.paramSymss.find(_.headOption.fold(false)(_.isTerm)).getOrElse(Nil) - - case Some(maybeSum) => - Expr.summon[Mirror.Of[T]] match { - case Some('{$m: mt { type MirroredElemTypes = met}}) => - - def extractTupleTypes(tpe: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tpe match { - case AppliedType(_, List(x: TypeRepr, xs: TypeRepr)) => extractTupleTypes(xs, x :: acc) - case _ => acc.reverse - } - - extractTupleTypes(TypeRepr.of[met], Nil).map(_.typeSymbol) - - case _ => - report.errorAndAbort(s"No Mirror found for ${tpe.show}") - } - - case None => - report.errorAndAbort(s"${tpe.show} is not case class or the root of a sealed family of types") - } - } - - def allAnnotationsCommon[A: Type, T: Type, Out](typeAnnotations: Boolean)( - makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] - )(using quotes: Quotes): Expr[Out] = { - import quotes.reflect.* - errorIfInvalidAnnotation[A] - val tpe = TypeRepr.of[T] - val annotations = productOrSumSymbols[T].map { symbol => - findAnnotation[A](tpe, symbol, typeAnnotations) match { - case Some(expr) =>'{Some($expr)} - case None => '{None} - } - } - - listExprToResult[HNil, Out]('{HNil: HNil}, annotations.reverse)(makeResult) - } - - def allAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[Annotations[A, T]] = { - allAnnotationsCommon[A, T, Annotations[A, T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => - '{ - new Annotations[A, T] { - override type Out = Acc - override def apply(): Acc = $acc - } - } - } - } - - def allTypeAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[TypeAnnotations[A, T]] = { - allAnnotationsCommon[A, T, TypeAnnotations[A, T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => - '{ - new TypeAnnotations[A, T] { - override type Out = Acc - override def apply(): Acc = $acc - } - } - } - } - - def allAnnotationsForTypeCommon[T: Type, Out](typeAnnotations: Boolean)( - makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] - )(using quotes: Quotes): Expr[Out] = { - import quotes.reflect.* - val tpe = TypeRepr.of[T] - val annotationLists = productOrSumSymbols[T].map { symbol => - val annotations = if(typeAnnotations) - annotationsFromType(tpe, tpe.memberType(symbol)) - else - symbol.annotations - listExprToHList(annotations.map(_.asExpr)) - } - listExprToResult[HNil, Out]('{HNil: HNil}, annotationLists.reverse)(makeResult) - } - - def allAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllAnnotations[T]] = { - allAnnotationsForTypeCommon[T, AllAnnotations[T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => - '{ - new AllAnnotations[T] { - override type Out = Acc - override def apply(): Out = $acc - } - } - } - } - - def allTypeAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllTypeAnnotations[T]] = { - allAnnotationsForTypeCommon[T, AllTypeAnnotations[T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => - '{ - new AllTypeAnnotations[T] { - override type Out = Acc - override def apply(): Out = $acc - } - } - } - } -} +/* + * Copyright (c) 2015-9 Alexandre Archambault + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.compiletime.* +import scala.deriving.* +import scala.quoted.* + +trait AnnotationScalaCompat { + inline given[A, T]: Annotation[A, T] = ${AnnotationMacros.singleAnnotationForType[A, T]} + inline given[A, T]: Annotation[Option[A], T] = ${AnnotationMacros.singleOptAnnotationForType[A, T]} +} + +trait AnnotationsScalaCompat { + inline transparent given[A, T]: Annotations[A, T] = ${AnnotationMacros.allAnnotations[A, T]} +} + +trait TypeAnnotationsScalaCompat { + inline transparent given[A, T]: TypeAnnotations[A, T] = ${AnnotationMacros.allTypeAnnotations[A, T]} +} + +trait AllAnnotationsScalaCompat { + inline transparent given[T]: AllAnnotations[T] = ${AnnotationMacros.allAnnotationsForType[T]} +} + +trait AllTypeAnnotationsScalaCompat { + inline transparent given[T]: AllTypeAnnotations[T] = ${AnnotationMacros.allTypeAnnotationsForType[T]} +} + +object AnnotationMacros { + + private def errorIfInvalidAnnotation[A: Type](using quotes: Quotes): Unit = { + import quotes.reflect.* + + val tpe = TypeRepr.of[A] + val flags = tpe.typeSymbol.flags + if (flags.is(Flags.Abstract) || flags.is(Flags.Trait)) { + report.errorAndAbort(s"Bad annotation type ${tpe.show} is abstract") + } + } + + private def annotationsFromType(using quotes: Quotes)(enclosing: quotes.reflect.TypeRepr, tpe: quotes.reflect.TypeRepr): List[quotes.reflect.Term] = { + import quotes.reflect.* + tpe match { + case AnnotatedType(rest, term) => + term :: annotationsFromType(enclosing, rest) + //case ClassInfo(_, _, parents) => parents.flatMap(fromType(enclosing, _)) + case ref @ TypeRef(_, _) if ref.typeSymbol.isAliasType => annotationsFromType(enclosing, enclosing.memberType(ref.typeSymbol)) + case TypeBounds(low, hi) if low == hi => annotationsFromType(enclosing, low) + case _ => + Nil + } + } + + private def findAnnotation[A: Type](using quotes: Quotes)(tpe: quotes.reflect.TypeRepr, symbol: quotes.reflect.Symbol, typeAnnotations: Boolean = false): Option[Expr[A]] = { + import quotes.reflect.* + val annotationType = TypeRepr.of[A] + + val annotations = if (typeAnnotations) + annotationsFromType(tpe, tpe.memberType(symbol)) + else + symbol.annotations + + annotations.find(_.tpe <:< annotationType).map(_.asExprOf[A]) + } + + private def singleAnnotationForTypeCommon[A: Type, T: Type](using quotes: Quotes): Option[Expr[A]] = { + import quotes.reflect.* + errorIfInvalidAnnotation[A] + findAnnotation[A](TypeRepr.of[T], TypeRepr.of[T].typeSymbol) + } + + def singleAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[A, T]] = { + import quotes.reflect.* + singleAnnotationForTypeCommon[A, T] match { + case Some(expr) => '{Annotation.mkAnnotation($expr)} + case None => report.errorAndAbort(s"No ${Type.show[A]} annotation found on ${Type.show[T]}") + } + } + + def singleOptAnnotationForType[A: Type, T: Type](using quotes: Quotes): Expr[Annotation[Option[A], T]] = { + import quotes.reflect.* + singleAnnotationForTypeCommon[A, T] match { + case Some(expr) => '{Annotation.mkAnnotation(Some($expr))} + case None => '{Annotation.mkAnnotation(None)} + } + } + + private def productOrSumSymbols[T: Type](using quotes: Quotes): Seq[quotes.reflect.Symbol] = { + import quotes.reflect.* + val tpe = TypeRepr.of[T] + + tpe.classSymbol match { + case Some(clazzSym) if clazzSym.flags.is(Flags.Case) => + clazzSym.primaryConstructor.paramSymss.find(_.headOption.fold(false)(_.isTerm)).getOrElse(Nil) + + case Some(maybeSum) => + Expr.summon[Mirror.Of[T]] match { + case Some('{$m: mt { type MirroredElemTypes = met}}) => + + def extractTupleTypes(tpe: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tpe match { + case AppliedType(_, List(x: TypeRepr, xs: TypeRepr)) => extractTupleTypes(xs, x :: acc) + case _ => acc.reverse + } + + extractTupleTypes(TypeRepr.of[met], Nil).map(_.typeSymbol) + + case _ => + report.errorAndAbort(s"No Mirror found for ${tpe.show}") + } + + case None => + report.errorAndAbort(s"${tpe.show} is not case class or the root of a sealed family of types") + } + } + + def allAnnotationsCommon[A: Type, T: Type, Out](typeAnnotations: Boolean)( + makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] + )(using quotes: Quotes): Expr[Out] = { + import quotes.reflect.* + errorIfInvalidAnnotation[A] + val tpe = TypeRepr.of[T] + val annotations = productOrSumSymbols[T].map { symbol => + findAnnotation[A](tpe, symbol, typeAnnotations) match { + case Some(expr) =>'{Some($expr)} + case None => '{None} + } + } + + listExprToResult[HNil, Out]('{HNil: HNil}, annotations.reverse)(makeResult) + } + + def allAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[Annotations[A, T]] = { + allAnnotationsCommon[A, T, Annotations[A, T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new Annotations[A, T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + } + } + + def allTypeAnnotations[A: Type, T: Type](using quotes: Quotes): Expr[TypeAnnotations[A, T]] = { + allAnnotationsCommon[A, T, TypeAnnotations[A, T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new TypeAnnotations[A, T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + } + } + + def allAnnotationsForTypeCommon[T: Type, Out](typeAnnotations: Boolean)( + makeResult: [Acc <: HList] => Type[Acc] ?=> Expr[Acc] => Expr[Out] + )(using quotes: Quotes): Expr[Out] = { + import quotes.reflect.* + val tpe = TypeRepr.of[T] + val annotationLists = productOrSumSymbols[T].map { symbol => + val annotations = if(typeAnnotations) + annotationsFromType(tpe, tpe.memberType(symbol)) + else + symbol.annotations + listExprToHList(annotations.map(_.asExpr)) + } + listExprToResult[HNil, Out]('{HNil: HNil}, annotationLists.reverse)(makeResult) + } + + def allAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllAnnotations[T]] = { + allAnnotationsForTypeCommon[T, AllAnnotations[T]](false) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new AllAnnotations[T] { + override type Out = Acc + override def apply(): Out = $acc + } + } + } + } + + def allTypeAnnotationsForType[T: Type](using quotes: Quotes): Expr[AllTypeAnnotations[T]] = { + allAnnotationsForTypeCommon[T, AllTypeAnnotations[T]](true) { [Acc <: HList] => (tpe: Type[Acc]) ?=> (acc: Expr[Acc]) => + '{ + new AllTypeAnnotations[T] { + override type Out = Acc + override def apply(): Out = $acc + } + } + } + } +} diff --git a/core/src/main/scala-3/shapeless/coproduct.scala b/core/src/main/scala-3/shapeless/coproduct.scala index e961b8924..2b964a9c2 100644 --- a/core/src/main/scala-3/shapeless/coproduct.scala +++ b/core/src/main/scala-3/shapeless/coproduct.scala @@ -1,28 +1,27 @@ -package shapeless - -trait CoproductScalaCompat { - - type CoproductToTuple[C <: Coproduct] <: scala.Tuple = C match { - case CNil => EmptyTuple - case h :+: t => h *: CoproductToTuple[t] - } - type TupleToCoproduct[T <: scala.Tuple] <: Coproduct = T match { - case EmptyTuple => CNil - case h *: t => h :+: TupleToCoproduct[t] - } - - type HListToCoproduct[L <: HList] <: Coproduct = L match { - case HNil => CNil - case h :: t => h :+: t - } - - def extractCoproduct[C <: Coproduct](coproduct: C): scala.Tuple.Union[CoproductToTuple[C]] = coproduct match { - case Inl(head) => head.asInstanceOf[scala.Tuple.Union[CoproductToTuple[C]]] - case Inr(tail) => extractCoproduct(tail.asInstanceOf[C]) - case err: CNil => err.impossible - } - - def coproductFromOrdinal[T <: scala.Tuple](a: scala.Tuple.Union[T], ordinal: Int): TupleToCoproduct[T] = - if ordinal == 0 then Inl(a).asInstanceOf[TupleToCoproduct[T]] - else Inr(coproductFromOrdinal(a, ordinal - 1)).asInstanceOf[TupleToCoproduct[T]] -} +package shapeless + +trait CoproductScalaCompat { + + type CoproductToTuple[C <: Coproduct] <: scala.Tuple = C match { + case CNil => EmptyTuple + case h :+: t => h *: CoproductToTuple[t] + } + type TupleToCoproduct[T <: scala.Tuple] <: Coproduct = T match { + case EmptyTuple => CNil + case h *: t => h :+: TupleToCoproduct[t] + } + + type HListToCoproduct[L <: HList] <: Coproduct = L match { + case HNil => CNil + case h :: t => h :+: t + } + + def extractCoproduct[C <: Coproduct](coproduct: C): scala.Tuple.Union[CoproductToTuple[C]] = coproduct match { + case Inl(head) => head.asInstanceOf[scala.Tuple.Union[CoproductToTuple[C]]] + case Inr(tail) => extractCoproduct(tail.asInstanceOf[C]) + } + + def coproductFromOrdinal[T <: scala.Tuple](a: scala.Tuple.Union[T], ordinal: Int): TupleToCoproduct[T] = + if ordinal == 0 then Inl(a).asInstanceOf[TupleToCoproduct[T]] + else Inr(coproductFromOrdinal(a, ordinal - 1)).asInstanceOf[TupleToCoproduct[T]] +} diff --git a/core/src/main/scala-3/shapeless/default.scala b/core/src/main/scala-3/shapeless/default.scala index bed8c9ba3..adb25f062 100644 --- a/core/src/main/scala-3/shapeless/default.scala +++ b/core/src/main/scala-3/shapeless/default.scala @@ -1,79 +1,81 @@ -package shapeless - -import scala.quoted.* - -trait DefaultScalaCompat { - transparent inline given materialize[T]: Default[T] = ${DefaultScalaCompat.defaultImpl[T]} -} - -object DefaultScalaCompat { - def defaultImpl[T: Type](using quotes: Quotes): Expr[Default[T]] = { - import quotes.reflect.* - val tpe = TypeRepr.of[T] - - val defaultConstructorMethodNames = "$lessinit$greater$default$" - - tpe.classSymbol match { - case Some(classSymbol) => - - if (classSymbol.moduleClass == classSymbol) { - '{ - new Default[T] { - override type Out = HNil - override def apply(): HNil = HNil - } - } - } - else if (classSymbol.flags.is(Flags.Abstract) || classSymbol.flags.is(Flags.Trait)) { - report.throwError(s"${tpe.show} is abstract") - } - else { - val constructorParams = classSymbol.primaryConstructor.paramSymss - if(constructorParams.sizeIs > 1) { - report.throwError(s"Found more than one parameter list for ${tpe.show}") - } - - val constructorParamsSize = constructorParams.head.size - if(constructorParamsSize == 0) { - report.throwError(s"${tpe.show} has an empty constructor") - } - - val moduleClass = classSymbol.companionModule.moduleClass - val defaultMethods = (1 to constructorParamsSize).map { i => - moduleClass.declaredMethod(defaultConstructorMethodNames + i).headOption - } - - val defaultExprs = defaultMethods.map { - case Some(method) => - val DefDef(_, _, tpeTree, optDefault) = method.tree - val default = optDefault.getOrElse( - report.throwError("Found empty tree for default. Make sure that the compiler option -Yretain-trees is enabled") - ) - - tpeTree.tpe.asType match { - case '[t2] => '{Some(${default.asExpr}.asInstanceOf[t2])} - } - - case None => '{None} - } - - def result[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[Any]]): Expr[Default[T]] = - rest match { - case Nil => '{ - new Default[T] { - override type Out = Acc - override def apply(): Acc = $acc - } - } - case Seq('{$head: tpe}, tail*) => - result('{new ::($head, $acc)}, tail) - } - - result('{HNil: HNil}, defaultExprs.reverse) - } - - case _ => - report.throwError(s"Invalid type ${tpe.show}. Expected a class.") - } - } -} +package shapeless + +import scala.quoted.* + +trait DefaultScalaCompat { + transparent inline given materialize[T]: Default[T] = ${DefaultScalaCompat.defaultImpl[T]} +} + +object DefaultScalaCompat { + def defaultImpl[T: Type](using quotes: Quotes): Expr[Default[T]] = { + import quotes.reflect.* + val tpe = TypeRepr.of[T] + + val defaultConstructorMethodNames = "$lessinit$greater$default$" + + tpe.classSymbol match { + case Some(classSymbol) => + + if (classSymbol.moduleClass == classSymbol) { + '{ + new Default[T] { + override type Out = HNil + override def apply(): HNil = HNil + } + } + } + else if (classSymbol.flags.is(Flags.Abstract) || classSymbol.flags.is(Flags.Trait)) { + report.errorAndAbort(s"${tpe.show} is abstract") + } + else { + val constructorParams = classSymbol.primaryConstructor.paramSymss + if(constructorParams.sizeIs > 1) { + report.errorAndAbort(s"Found more than one parameter list for ${tpe.show}") + } + + val constructorParamsSize = constructorParams.head.size + if(constructorParamsSize == 0) { + report.errorAndAbort(s"${tpe.show} has an empty constructor") + } + + val moduleClass = classSymbol.companionModule.moduleClass + val defaultMethods = (1 to constructorParamsSize).map { i => + moduleClass.declaredMethod(defaultConstructorMethodNames + i).headOption + } + + val defaultExprs = defaultMethods.map { + case Some(method) => + method.tree match { + case DefDef(_, _, tpeTree, optDefault) => + val default = optDefault.getOrElse( + report.errorAndAbort("Found empty tree for default. Make sure that the compiler option -Yretain-trees is enabled") + ) + + tpeTree.tpe.asType match { + case '[t2] => '{Some(${default.asExpr}.asInstanceOf[t2])} + } + case _ => '{None} + } + case None => '{None} + } + + def result[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[Any]]): Expr[Default[T]] = + rest match { + case Nil => '{ + new Default[T] { + override type Out = Acc + override def apply(): Acc = $acc + } + } + case Seq('{$head: tpe}, tail*) => + result('{new ::($head, $acc)}, tail) + } + + result('{HNil: HNil}, defaultExprs.reverse) + } + + case _ => + report.errorAndAbort(s"Invalid type ${tpe.show}. Expected a class.") + } + } +} diff --git a/core/src/main/scala-3/shapeless/records.scala b/core/src/main/scala-3/shapeless/records.scala index ed8a9e2ac..4ebfc51ff 100644 --- a/core/src/main/scala-3/shapeless/records.scala +++ b/core/src/main/scala-3/shapeless/records.scala @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2011-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import shapeless.labelled.FieldType - -import scala.compiletime._ -import scala.quoted._ - -trait RecordScalaCompat { - inline def applyDynamic(inline method: String)(inline rec: (String, Any)*): HNil = - //inline if method != "apply" then ??? //error(s"this method must be called as 'apply' not $method") - //else inline if rec.nonEmpty then ??? //error("this method must be called with named arguments") - /*else*/ HNil - - transparent inline def applyDynamicNamed(inline method: String)(inline rec: (String, Any)*): HList = - ${ RecordScalaCompat.applyDynamicNamedImpl('method)('rec) } -} -object RecordScalaCompat { - def applyDynamicNamedImpl(method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[HList] = { - import quotes.reflect.report - val methodString = method.valueOrError - if methodString != "apply" then - report.throwError(s"this method must be called as 'apply' not '$methodString'") - - rec match { - case Varargs(values) => - def transform[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[(String, Any)]]): Expr[HList] = - rest match { - case Nil => acc - case Seq('{($keyExpr: String, $value: tp)}, tail*) => - import quotes.reflect._ - keyExpr.asTerm match { - case Literal(const) => ConstantType(const).asType - } match { - case '[keyTpe] => transform('{$value.asInstanceOf[FieldType[keyTpe, tp]] :: $acc}, tail) - } - - case _ => - report.throwError("Got invalid arguments in varargs") - } - - transform('{HNil}, values.reverse) - - case _ => - report.throwError("this method must be called with vararg arguments") - } - } -} +/* + * Copyright (c) 2011-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import shapeless.labelled.FieldType + +import scala.compiletime._ +import scala.quoted._ + +trait RecordScalaCompat { + inline def applyDynamic(inline method: String)(inline rec: (String, Any)*): HNil = + //inline if method != "apply" then ??? //error(s"this method must be called as 'apply' not $method") + //else inline if rec.nonEmpty then ??? //error("this method must be called with named arguments") + /*else*/ HNil + + transparent inline def applyDynamicNamed(inline method: String)(inline rec: (String, Any)*): HList = + ${ RecordScalaCompat.applyDynamicNamedImpl('method)('rec) } +} +object RecordScalaCompat { + def applyDynamicNamedImpl(method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[HList] = { + import quotes.reflect.report + val methodString = method.valueOrAbort + if methodString != "apply" then + report.errorAndAbort(s"this method must be called as 'apply' not '$methodString'") + + rec match { + case Varargs(values) => + def transform[Acc <: HList: Type](acc: Expr[Acc], rest: Seq[Expr[(String, Any)]]): Expr[HList] = + rest match { + case Nil => acc + case Seq('{($keyExpr: String, $value: tp)}, tail*) => + import quotes.reflect._ + keyExpr.asTerm match { + case Literal(const) => ConstantType(const).asType + } match { + case '[keyTpe] => transform('{$value.asInstanceOf[FieldType[keyTpe, tp]] :: $acc}, tail) + } + + case _ => + report.errorAndAbort("Got invalid arguments in varargs") + } + + transform('{HNil}, values.reverse) + + case _ => + report.errorAndAbort("this method must be called with vararg arguments") + } + } +} diff --git a/core/src/main/scala-3/shapeless/test/illTyped.scala b/core/src/main/scala-3/shapeless/test/illTyped.scala index 16729495f..0cd6a8792 100644 --- a/core/src/main/scala-3/shapeless/test/illTyped.scala +++ b/core/src/main/scala-3/shapeless/test/illTyped.scala @@ -1,69 +1,69 @@ -package shapeless.test - -import java.util.regex.Pattern -import scala.compiletime.* -import scala.compiletime.testing.* -import scala.quoted.* - -object illTyped { - - inline def apply(inline code: String): Unit = - ${impl('{typeCheckErrors(code)}, '{None})} - - inline def apply(inline code: String, inline expected: String): Unit = - ${impl('{typeCheckErrors(code)}, '{Some(expected)})} - - private given FromExpr[ErrorKind] with { - override def unapply(x: Expr[ErrorKind])(using Quotes): Option[ErrorKind] = x match { - case '{ErrorKind.Parser} => Some(ErrorKind.Parser) - case '{ErrorKind.Typer} => Some(ErrorKind.Typer) - case _ => None - } - } - - private given FromExpr[Error] with { - override def unapply(x: Expr[Error])(using Quotes): Option[Error] = { - x match { - case '{Error($a, $b, $c, $d)} => - (a.asExprOf[String], b.asExprOf[String], c.asExprOf[Int], d.asExprOf[ErrorKind]) match { - case (Expr(message), Expr(lineContent), Expr(column), Expr(errorKind)) => - Some(Error(message, lineContent, column, errorKind)) - case _ => None - } - case _ => None - } - } - } - - def impl(errorsE: Expr[List[Error]], expectedE: Expr[Option[String]])(using quotes: Quotes): Expr[Unit] = { - import quotes.reflect.* - - val errors = errorsE.asTerm match { - case Inlined(_, _, Apply(_, List(errorsVararg))) => - errorsVararg.asExprOf[Seq[Error]] match { - case Varargs(Exprs(es)) => es - case _ => report.throwError("Unexpected errors structure") - } - case _ => report.throwError("Unexpected errors structure") - } - val expectedOpt = expectedE.valueOrError - - errors.find(_.kind == ErrorKind.Parser).foreach { e => - report.throwError("Parsing failed.\n" + e.message) - } - - if (errors.isEmpty) { - report.throwError("Type-checking succeeded unexpectedly.\nExpected some error.") - } - - expectedOpt.foreach { expected => - val expectedPattern: Pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) - - if (!errors.exists(e => expectedPattern.matcher(e.message).matches)) { - report.throwError("Type-checking failed in an unexpected way.\n" + expected + "\nActual error: "+ errors.head.message) - } - } - - '{()} - } -} +package shapeless.test + +import java.util.regex.Pattern +import scala.compiletime.* +import scala.compiletime.testing.* +import scala.quoted.* + +object illTyped { + + inline def apply(inline code: String): Unit = + ${impl('{typeCheckErrors(code)}, '{None})} + + inline def apply(inline code: String, inline expected: String): Unit = + ${impl('{typeCheckErrors(code)}, '{Some(expected)})} + + private given FromExpr[ErrorKind] with { + override def unapply(x: Expr[ErrorKind])(using Quotes): Option[ErrorKind] = x match { + case '{ErrorKind.Parser} => Some(ErrorKind.Parser) + case '{ErrorKind.Typer} => Some(ErrorKind.Typer) + case _ => None + } + } + + private given FromExpr[Error] with { + override def unapply(x: Expr[Error])(using Quotes): Option[Error] = { + x match { + case '{Error($a, $b, $c, $d)} => + (a.asExprOf[String], b.asExprOf[String], c.asExprOf[Int], d.asExprOf[ErrorKind]) match { + case (Expr(message), Expr(lineContent), Expr(column), Expr(errorKind)) => + Some(Error(message, lineContent, column, errorKind)) + case _ => None + } + case _ => None + } + } + } + + def impl(errorsE: Expr[List[Error]], expectedE: Expr[Option[String]])(using quotes: Quotes): Expr[Unit] = { + import quotes.reflect.* + + val errors = errorsE.asTerm match { + case Inlined(_, _, Apply(_, List(errorsVararg))) => + errorsVararg.asExprOf[Seq[Error]] match { + case Varargs(Exprs(es)) => es + case _ => report.errorAndAbort("Unexpected errors structure") + } + case _ => report.errorAndAbort("Unexpected errors structure") + } + val expectedOpt = expectedE.valueOrAbort + + errors.find(_.kind == ErrorKind.Parser).foreach { e => + report.errorAndAbort("Parsing failed.\n" + e.message) + } + + if (errors.isEmpty) { + report.errorAndAbort("Type-checking succeeded unexpectedly.\nExpected some error.") + } + + expectedOpt.foreach { expected => + val expectedPattern: Pattern = Pattern.compile(expected, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) + + if (!errors.exists(e => expectedPattern.matcher(e.message).matches)) { + report.errorAndAbort("Type-checking failed in an unexpected way.\n" + expected + "\nActual error: "+ errors.head.message) + } + } + + '{()} + } +} diff --git a/core/src/main/scala-3/shapeless/typeable.scala b/core/src/main/scala-3/shapeless/typeable.scala index 999d8375c..48ea1baaa 100644 --- a/core/src/main/scala-3/shapeless/typeable.scala +++ b/core/src/main/scala-3/shapeless/typeable.scala @@ -1,334 +1,333 @@ -/* - * Copyright (c) 2011-18 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.annotation.tailrec -import scala.compiletime.* -import scala.quoted.* -import scala.deriving.* -import shapeless.Typeable.{instance, safeSimpleName} - -trait TypeableScalaCompat { - - /** - * Typeable instance for singleton reference types - * - * @param value The singleton value - * - * @param name The name of the singleton - * - * @param serializable Whether the instance should be - * serializable. For singleton types of object definitions - * and symbols, this should be true, since they preserve - * their identity after serialization/deserialization. - * For other cases, it should be false, since the deserialized - * instance wouldn't work correctly. - */ - def referenceSingletonTypeable[T](value: T, name: String, serializable: Boolean): Typeable[T] = - new Typeable[T] { - def describe = s"$name.type" - - def cast(t: Any): Option[T] = - if (t.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) Some(value) else None - - @throws(classOf[java.io.IOException]) - private def writeObject(out: java.io.ObjectOutputStream): Unit = - if (serializable) out.defaultWriteObject() - else throw new java.io.NotSerializableException("referenceSingletonTypeable") - } - - /** Typeable instance for intersection types with typeable parents */ - def intersectionTypeable[T](parents: Array[Typeable[_]]): Typeable[T] = - instance(parents.map(_.describe).mkString(" & ")) { t => - if (t != null && parents.forall(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None - } - - /** Typeable instance for union types with typeable disjuncts */ - def unionTypeable[T](parents: Seq[Typeable[_]]): Typeable[T] = - instance(parents.map(_.describe).mkString(" | ")) { t => - if (t != null && parents.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None - } - - /** Typeable instance for polymorphic case classes with typeable elements */ - def caseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]]): Typeable[T] = - namedCaseClassTypeable(erased, fields, s"${safeSimpleName(erased)}[${fields.map(_.describe).mkString(",")}]") - - /** Typeable instance for polymorphic case classes with typeable elements, specifying the name explicitly. */ - def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = - instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => - if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { - val cp = t.asInstanceOf[Product] - val ct = t.asInstanceOf[T] - val f = cp.productIterator.toList - if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None - } else None - } - - /** Typeable instance for polymorphic sums with typeable elements. */ - def namedSumTypeable[T](elems: Seq[Typeable[_]], name: String): Typeable[T] = - instance(name) { t => - if (elems.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None - } -} - -trait LowPriorityTypeableScalaCompat { - inline def mkDefaultTypeable[T]: Typeable[T] = ${ LowPriorityTypeableScalaCompat.impl[T] } - - inline given [T]: Typeable[T] = mkDefaultTypeable[T] -} - -object LowPriorityTypeableScalaCompat { - import Typeable._ - - def impl[T: Type](using Quotes): Expr[Typeable[T]] = { - import quotes.reflect._ - import util._ - - val TypeableType = TypeRepr.of[Typeable[_]] match { - case tp: AppliedType => tp.tycon - } - - val target = TypeRepr.of[T] - - def isAbstract(tp: TypeRepr): Boolean = - tp.typeSymbol.isAbstractType || - (tp match { - case tp: AppliedType => - isAbstract(tp.tycon) || tp.args.exists(isAbstract) - case _ => false - }) - - def normalize(tp: TypeRepr): TypeRepr = tp match { - case tp: TypeBounds => tp.low - case tp => tp - } - - def simpleName(tp: TypeRepr): String = - normalize(tp).dealias match { - case tp: AppliedType => - simpleName(tp.tycon) + tp.args.map(simpleName).mkString("[", ", ", "]") - case TypeRef(_, name) => name - case tp => tp.show - } - - def collectConjuncts(tp: TypeRepr): List[TypeRepr] = tp match { - case tp: AndType => - collectConjuncts(tp.left) ++ collectConjuncts(tp.right) - case tp => List(tp) - } - - def collectDisjuncts(tp: TypeRepr): List[TypeRepr] = tp match { - case tp: OrType => - collectDisjuncts(tp.left) ++ collectDisjuncts(tp.right) - case tp => List(tp) - } - - def summonAllTypeables(tps: Seq[TypeRepr]): Option[Expr[Seq[Typeable[_]]]] = { - val ttps = tps.map(tp => TypeableType.appliedTo(tp)) - val instances = ttps.flatMap(ttp => Implicits.search(ttp) match { - case iss: ImplicitSearchSuccess => List(iss.tree.asExprOf[Typeable[_]]) - case _: ImplicitSearchFailure => Nil - }) - - if (tps.length == instances.length) Some(Expr.ofSeq(instances)) - else None - } - - def mkCaseClassTypeable = { - val sym = target.classSymbol.get - val fields = sym.declaredFields - val caseFields = sym.caseFields.filter(f => fields.contains(f)) - def fieldTpe(f: Symbol) = f.tree match { - case tree: ValDef => tree.tpt.tpe - } - if (!fields.forall(f => caseFields.contains(f) || !isAbstract(fieldTpe(f)))) { - report.throwError(s"No Typeable for case class ${target.show} with non-case fields") - } else { - val fieldTps = caseFields.map(f => target.memberType(f)) - summonAllTypeables(fieldTps) match { - case None => - report.throwError(s"Missing Typeable for field of case class ${target.show}") - case Some(ftps) => - val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] - val name = Expr(simpleName(target)) - - '{ namedCaseClassTypeable($clazz, $ftps.toArray, $name) } - } - } - } - - def mkSumTypeable = { - val r = new ReflectionUtils(quotes) - import r._ - - Mirror(target) match { - case Some(rm) => - val elemTps = rm.MirroredElemTypes - summonAllTypeables(elemTps) match { - case None => - report.throwError(s"Missing Typeable for child of sum type ${target.show}") - case Some(etps) => - val name = Expr(simpleName(target)) - - '{ namedSumTypeable[T]($etps, $name) } - } - - case None => - report.throwError(s"Typeable for sum type ${target.show} with no Mirror") - } - } - - def mkNamedSimpleTypeable = { - val name = Expr(simpleName(target)) - val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] - '{ namedSimpleTypeable($clazz, $name) } - } - - target.dealias match { - case tp: TermRef => - val ident = Ident(tp).asExprOf[T] - val sym = tp.termSymbol - val name = Expr(sym.name.toString) - val serializable = Expr(sym.flags.is(Flags.Module)) - '{ referenceSingletonTypeable[T]($ident, $name, $serializable) } - - case ConstantType(c) => - val value = Literal(c).asExprOf[T] - val name = Expr(target.widen.typeSymbol.name.toString) - '{ valueSingletonTypeable[T]($value, $name) } - - case tp: TypeRef => - val qual = tp.qualifier match { - case NoPrefix() => None - case tp: ThisType => Some(tp.tref) - case tp => Some(tp) - } - - val sym = tp.typeSymbol - - def normalizeModuleClass(sym: Symbol): Symbol = - if (sym.flags.is(Flags.Module)) sym.companionModule else sym - - val owner = normalizeModuleClass(sym.owner) - - qual match { - case Some(_) if sym.flags.is(Flags.Case) => mkCaseClassTypeable - case None => - mkNamedSimpleTypeable - case Some(tp: TypeRef) if normalizeModuleClass(tp.typeSymbol) == owner => - mkNamedSimpleTypeable - case Some(tp: TermRef) if normalizeModuleClass(tp.termSymbol) == owner => - mkNamedSimpleTypeable - case Some(_) if sym.flags.is(Flags.Sealed) => mkSumTypeable - case _ => - report.throwError(s"No Typeable for type ${target.show} with a dependent prefix") - } - - case tp: AppliedType => - val tycon = tp.tycon - val args = tp.args - - if (tp.typeSymbol.flags.is(Flags.Case)) mkCaseClassTypeable - else if (tp.typeSymbol.flags.is(Flags.Sealed)) mkSumTypeable - else report.throwError(s"No Typeable for parametrized type ${target.show}") - - - case tp: AndType => - val conjuncts = collectConjuncts(tp) - summonAllTypeables(conjuncts) match { - case Some(ctps) => - '{ intersectionTypeable($ctps.toArray) } - case None => - report.throwError(s"No Typeable for & type ${target.show} with missing conjunct(s)") - } - - case tp: OrType => - val disjuncts = collectDisjuncts(tp) - summonAllTypeables(disjuncts) match { - case Some(dtps) => - '{ unionTypeable($dtps) } - case None => - report.throwError(s"No Typeable for | type ${target.show} with missing disjunct(s)") - } - - case other => - report.throwError(s"No Typeable for type ${target.show}") - } - } -} - -class ReflectionUtils[Q <: Quotes & Singleton](val q: Q) { - given q.type = q - import q.reflect._ - - case class Mirror( - MirroredType: TypeRepr, - MirroredMonoType: TypeRepr, - MirroredElemTypes: Seq[TypeRepr], - MirroredLabel: String, - MirroredElemLabels: Seq[String] - ) - - object Mirror { - def apply(mirror: Expr[scala.deriving.Mirror]): Option[Mirror] = { - val mirrorTpe = mirror.asTerm.tpe.widen - for { - mt <- findMemberType(mirrorTpe, "MirroredType") - mmt <- findMemberType(mirrorTpe, "MirroredMonoType") - mets <- findMemberType(mirrorTpe, "MirroredElemTypes") - ml <- findMemberType(mirrorTpe, "MirroredLabel") - mels <- findMemberType(mirrorTpe, "MirroredElemLabels") - } yield { - val mets0 = tupleTypeElements(mets) - val ConstantType(StringConstant(ml0)) = ml - val mels0 = tupleTypeElements(mels).map { case ConstantType(StringConstant(l)) => l } - Mirror(mt, mmt, mets0, ml0, mels0) - } - } - - def apply(tpe: TypeRepr): Option[Mirror] = { - val MirrorType = TypeRepr.of[scala.deriving.Mirror] - - val mtpe = Refinement(MirrorType, "MirroredType", TypeBounds(tpe, tpe)) - val instance = Implicits.search(mtpe) match { - case iss: ImplicitSearchSuccess => Some(iss.tree.asExprOf[scala.deriving.Mirror]) - case _: ImplicitSearchFailure => None - } - instance.flatMap(Mirror(_)) - } - } - - def tupleTypeElements(tp: TypeRepr): List[TypeRepr] = { - @tailrec def loop(tp: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tp match { - case AppliedType(pairTpe, List(hd: TypeRepr, tl: TypeRepr)) => loop(tl, hd :: acc) - case _ => acc - } - loop(tp, Nil).reverse - } - - def low(tp: TypeRepr): TypeRepr = tp match { - case tp: TypeBounds => tp.low - case tp => tp - } - - def findMemberType(tp: TypeRepr, name: String): Option[TypeRepr] = tp match { - case Refinement(_, `name`, tp) => Some(low(tp)) - case Refinement(parent, _, _) => findMemberType(parent, name) - case AndType(left, right) => findMemberType(left, name).orElse(findMemberType(right, name)) - case _ => None - } -} +/* + * Copyright (c) 2011-18 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.annotation.tailrec +import scala.compiletime.* +import scala.quoted.* +import scala.deriving.* +import shapeless.Typeable.{instance, safeSimpleName} + +trait TypeableScalaCompat { + + /** + * Typeable instance for singleton reference types + * + * @param value The singleton value + * + * @param name The name of the singleton + * + * @param serializable Whether the instance should be + * serializable. For singleton types of object definitions + * and symbols, this should be true, since they preserve + * their identity after serialization/deserialization. + * For other cases, it should be false, since the deserialized + * instance wouldn't work correctly. + */ + def referenceSingletonTypeable[T](value: T, name: String, serializable: Boolean): Typeable[T] = + new Typeable[T] { + def describe = s"$name.type" + + def cast(t: Any): Option[T] = + if (t.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) Some(value) else None + + @throws(classOf[java.io.IOException]) + private def writeObject(out: java.io.ObjectOutputStream): Unit = + if (serializable) out.defaultWriteObject() + else throw new java.io.NotSerializableException("referenceSingletonTypeable") + } + + /** Typeable instance for intersection types with typeable parents */ + def intersectionTypeable[T](parents: Array[Typeable[_]]): Typeable[T] = + instance(parents.map(_.describe).mkString(" & ")) { t => + if (t != null && parents.forall(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } + + /** Typeable instance for union types with typeable disjuncts */ + def unionTypeable[T](parents: Seq[Typeable[_]]): Typeable[T] = + instance(parents.map(_.describe).mkString(" | ")) { t => + if (t != null && parents.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } + + /** Typeable instance for polymorphic case classes with typeable elements */ + def caseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]]): Typeable[T] = + namedCaseClassTypeable(erased, fields, s"${safeSimpleName(erased)}[${fields.map(_.describe).mkString(",")}]") + + /** Typeable instance for polymorphic case classes with typeable elements, specifying the name explicitly. */ + def namedCaseClassTypeable[T](erased: Class[T], fields: Array[Typeable[_]], name: => String): Typeable[T] = + instance(s"$name[${fields.map(_.describe).mkString(",")}]") { t => + if (classOf[Product].isAssignableFrom(erased) && erased.isInstance(t)) { + val cp = t.asInstanceOf[Product] + val ct = t.asInstanceOf[T] + val f = cp.productIterator.toList + if ((f zip fields).forall { case (f, castF) => castF.cast(f).isDefined }) Some(ct) else None + } else None + } + + /** Typeable instance for polymorphic sums with typeable elements. */ + def namedSumTypeable[T](elems: Seq[Typeable[_]], name: String): Typeable[T] = + instance(name) { t => + if (elems.exists(_.cast(t).isDefined)) Some(t.asInstanceOf[T]) else None + } +} + +trait LowPriorityTypeableScalaCompat { + inline def mkDefaultTypeable[T]: Typeable[T] = ${ LowPriorityTypeableScalaCompat.impl[T] } + + inline given [T]: Typeable[T] = mkDefaultTypeable[T] +} + +object LowPriorityTypeableScalaCompat { + import Typeable._ + + def impl[T: Type](using Quotes): Expr[Typeable[T]] = { + import quotes.reflect._ + import util._ + + val TypeableType = TypeRepr.of[Typeable[_]] match { + case tp: AppliedType => tp.tycon + } + + val target = TypeRepr.of[T] + + def isAbstract(tp: TypeRepr): Boolean = + tp.typeSymbol.isAbstractType || + (tp match { + case tp: AppliedType => + isAbstract(tp.tycon) || tp.args.exists(isAbstract) + case _ => false + }) + + def normalize(tp: TypeRepr): TypeRepr = tp match { + case tp: TypeBounds => tp.low + case tp => tp + } + + def simpleName(tp: TypeRepr): String = + normalize(tp).dealias match { + case tp: AppliedType => + simpleName(tp.tycon) + tp.args.map(simpleName).mkString("[", ", ", "]") + case TypeRef(_, name) => name + case tp => tp.show + } + + def collectConjuncts(tp: TypeRepr): List[TypeRepr] = tp match { + case tp: AndType => + collectConjuncts(tp.left) ++ collectConjuncts(tp.right) + case tp => List(tp) + } + + def collectDisjuncts(tp: TypeRepr): List[TypeRepr] = tp match { + case tp: OrType => + collectDisjuncts(tp.left) ++ collectDisjuncts(tp.right) + case tp => List(tp) + } + + def summonAllTypeables(tps: Seq[TypeRepr]): Option[Expr[Seq[Typeable[_]]]] = { + val ttps = tps.map(tp => TypeableType.appliedTo(tp)) + val instances = ttps.flatMap(ttp => Implicits.search(ttp) match { + case iss: ImplicitSearchSuccess => List(iss.tree.asExprOf[Typeable[_]]) + case _: ImplicitSearchFailure => Nil + }) + + if (tps.length == instances.length) Some(Expr.ofSeq(instances)) + else None + } + + def mkCaseClassTypeable = { + val sym = target.classSymbol.get + val fields = sym.declaredFields + val caseFields = sym.caseFields.filter(f => fields.contains(f)) + def fieldTpe(f: Symbol) = f.tree match { + case tree: ValDef => tree.tpt.tpe + } + if (!fields.forall(f => caseFields.contains(f) || !isAbstract(fieldTpe(f)))) { + report.errorAndAbort(s"No Typeable for case class ${target.show} with non-case fields") + } else { + val fieldTps = caseFields.map(f => target.memberType(f)) + summonAllTypeables(fieldTps) match { + case None => + report.errorAndAbort(s"Missing Typeable for field of case class ${target.show}") + case Some(ftps) => + val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] + val name = Expr(simpleName(target)) + + '{ namedCaseClassTypeable($clazz, $ftps.toArray, $name) } + } + } + } + + def mkSumTypeable = { + val r = new ReflectionUtils(quotes) + import r._ + + Mirror(target) match { + case Some(rm) => + val elemTps = rm.MirroredElemTypes + summonAllTypeables(elemTps) match { + case None => + report.errorAndAbort(s"Missing Typeable for child of sum type ${target.show}") + case Some(etps) => + val name = Expr(simpleName(target)) + + '{ namedSumTypeable[T]($etps, $name) } + } + + case None => + report.errorAndAbort(s"Typeable for sum type ${target.show} with no Mirror") + } + } + + def mkNamedSimpleTypeable = { + val name = Expr(simpleName(target)) + val clazz = Ref(defn.Predef_classOf).appliedToType(target).asExprOf[Class[T]] + '{ namedSimpleTypeable($clazz, $name) } + } + + target.dealias match { + case tp: TermRef => + val ident = Ident(tp).asExprOf[T] + val sym = tp.termSymbol + val name = Expr(sym.name.toString) + val serializable = Expr(sym.flags.is(Flags.Module)) + '{ referenceSingletonTypeable[T]($ident, $name, $serializable) } + + case ConstantType(c) => + val value = Literal(c).asExprOf[T] + val name = Expr(target.widen.typeSymbol.name.toString) + '{ valueSingletonTypeable[T]($value, $name) } + + case tp: TypeRef => + val qual = tp.qualifier match { + case NoPrefix() => None + case tp: ThisType => Some(tp.tref) + case tp => Some(tp) + } + + val sym = tp.typeSymbol + + def normalizeModuleClass(sym: Symbol): Symbol = + if (sym.flags.is(Flags.Module)) sym.companionModule else sym + + val owner = normalizeModuleClass(sym.owner) + + qual match { + case Some(_) if sym.flags.is(Flags.Case) => mkCaseClassTypeable + case None => + mkNamedSimpleTypeable + case Some(tp: TypeRef) if normalizeModuleClass(tp.typeSymbol) == owner => + mkNamedSimpleTypeable + case Some(tp: TermRef) if normalizeModuleClass(tp.termSymbol) == owner => + mkNamedSimpleTypeable + case Some(_) if sym.flags.is(Flags.Sealed) => mkSumTypeable + case _ => + report.errorAndAbort(s"No Typeable for type ${target.show} with a dependent prefix") + } + + case tp: AppliedType => + val tycon = tp.tycon + val args = tp.args + + if (tp.typeSymbol.flags.is(Flags.Case)) mkCaseClassTypeable + else if (tp.typeSymbol.flags.is(Flags.Sealed)) mkSumTypeable + else report.errorAndAbort(s"No Typeable for parametrized type ${target.show}") + + + case tp: AndType => + val conjuncts = collectConjuncts(tp) + summonAllTypeables(conjuncts) match { + case Some(ctps) => + '{ intersectionTypeable($ctps.toArray) } + case None => + report.errorAndAbort(s"No Typeable for & type ${target.show} with missing conjunct(s)") + } + + case tp: OrType => + val disjuncts = collectDisjuncts(tp) + summonAllTypeables(disjuncts) match { + case Some(dtps) => + '{ unionTypeable($dtps) } + case None => + report.errorAndAbort(s"No Typeable for | type ${target.show} with missing disjunct(s)") + } + + case other => + report.errorAndAbort(s"No Typeable for type ${target.show}") + } + } +} + +class ReflectionUtils[Q <: Quotes & Singleton](val q: Q) { + given q.type = q + import q.reflect._ + + case class Mirror( + MirroredType: TypeRepr, + MirroredMonoType: TypeRepr, + MirroredElemTypes: Seq[TypeRepr], + MirroredLabel: String, + MirroredElemLabels: Seq[String] + ) + + object Mirror { + def apply(mirror: Expr[scala.deriving.Mirror]): Option[Mirror] = { + val mirrorTpe = mirror.asTerm.tpe.widen + for { + mt <- findMemberType(mirrorTpe, "MirroredType") + mmt <- findMemberType(mirrorTpe, "MirroredMonoType") + mets <- findMemberType(mirrorTpe, "MirroredElemTypes") + case ConstantType(StringConstant(ml0)) <- findMemberType(mirrorTpe, "MirroredLabel") + mels <- findMemberType(mirrorTpe, "MirroredElemLabels") + } yield { + val mets0 = tupleTypeElements(mets) + val mels0 = tupleTypeElements(mels).map { case ConstantType(StringConstant(l)) => l } + Mirror(mt, mmt, mets0, ml0, mels0) + } + } + + def apply(tpe: TypeRepr): Option[Mirror] = { + val MirrorType = TypeRepr.of[scala.deriving.Mirror] + + val mtpe = Refinement(MirrorType, "MirroredType", TypeBounds(tpe, tpe)) + val instance = Implicits.search(mtpe) match { + case iss: ImplicitSearchSuccess => Some(iss.tree.asExprOf[scala.deriving.Mirror]) + case _: ImplicitSearchFailure => None + } + instance.flatMap(Mirror(_)) + } + } + + def tupleTypeElements(tp: TypeRepr): List[TypeRepr] = { + @tailrec def loop(tp: TypeRepr, acc: List[TypeRepr]): List[TypeRepr] = tp match { + case AppliedType(pairTpe, List(hd: TypeRepr, tl: TypeRepr)) => loop(tl, hd :: acc) + case _ => acc + } + loop(tp, Nil).reverse + } + + def low(tp: TypeRepr): TypeRepr = tp match { + case tp: TypeBounds => tp.low + case tp => tp + } + + def findMemberType(tp: TypeRepr, name: String): Option[TypeRepr] = tp match { + case Refinement(_, `name`, tp) => Some(low(tp)) + case Refinement(parent, _, _) => findMemberType(parent, name) + case AndType(left, right) => findMemberType(left, name).orElse(findMemberType(right, name)) + case _ => None + } +} diff --git a/core/src/main/scala-3/shapeless/unions.scala b/core/src/main/scala-3/shapeless/unions.scala index 528ba5a4a..3da5ca3b5 100644 --- a/core/src/main/scala-3/shapeless/unions.scala +++ b/core/src/main/scala-3/shapeless/unions.scala @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2013-16 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import shapeless.labelled.FieldType - -import scala.quoted._ - -trait UnionScalaCompat { - transparent inline def applyDynamicNamed[U <: Coproduct](inline method: String)(inline rec: (String, Any)*): U = - ${ UnionScalaCompat.applyDynamicNamedImpl[U]('method)('rec) } -} -object UnionScalaCompat { - def applyDynamicNamedImpl[U <: Coproduct: Type](method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[U] = { - import quotes.reflect.report - val methodString = method.valueOrError - if methodString != "apply" then - report.throwError(s"this method must be called as 'apply' not '$methodString'") - - rec match { - case Varargs(Seq('{($keyExpr: String, $value: tp)})) => - import quotes.reflect._ - - keyExpr.asTerm match { - case Literal(const) => ConstantType(const).asType - } match { - case '[keyTpe] => - Expr.summon[ops.coproduct.Inject[U, FieldType[keyTpe, tp]]] match { - case Some(injectExpr) => '{$injectExpr($value.asInstanceOf[FieldType[keyTpe, tp]])} - case None => - report.throwError("Can not inject into coproduct") - } - } - - case Varargs(_) => - report.throwError("only one branch of a union may be inhabited") - - case _ => - report.throwError("this method must be called with vararg arguments") - } - } -} +/* + * Copyright (c) 2013-16 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import shapeless.labelled.FieldType + +import scala.quoted._ + +trait UnionScalaCompat { + transparent inline def applyDynamicNamed[U <: Coproduct](inline method: String)(inline rec: (String, Any)*): U = + ${ UnionScalaCompat.applyDynamicNamedImpl[U]('method)('rec) } +} +object UnionScalaCompat { + def applyDynamicNamedImpl[U <: Coproduct: Type](method: Expr[String])(rec: Expr[Seq[(String, Any)]])(using Quotes): Expr[U] = { + import quotes.reflect.report + val methodString = method.valueOrAbort + if methodString != "apply" then + report.errorAndAbort(s"this method must be called as 'apply' not '$methodString'") + + rec match { + case Varargs(Seq('{($keyExpr: String, $value: tp)})) => + import quotes.reflect._ + + keyExpr.asTerm match { + case Literal(const) => ConstantType(const).asType + } match { + case '[keyTpe] => + Expr.summon[ops.coproduct.Inject[U, FieldType[keyTpe, tp]]] match { + case Some(injectExpr) => '{$injectExpr($value.asInstanceOf[FieldType[keyTpe, tp]])} + case None => + report.errorAndAbort("Can not inject into coproduct") + } + } + + case Varargs(_) => + report.errorAndAbort("only one branch of a union may be inhabited") + + case _ => + report.errorAndAbort("this method must be called with vararg arguments") + } + } +} diff --git a/core/src/main/scala/shapeless/ops/tuples.scala b/core/src/main/scala/shapeless/ops/tuples.scala index e8ec9af30..e9c82f184 100644 --- a/core/src/main/scala/shapeless/ops/tuples.scala +++ b/core/src/main/scala/shapeless/ops/tuples.scala @@ -1,1340 +1,1340 @@ -/* - * Copyright (c) 2013-15 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless -package ops - -import scala.annotation.implicitNotFound - -object tuple { - import shapeless.ops.{ hlist => hl } - - /** - * Type class witnessing that this tuple is composite and providing access to head and tail. - * - * @author Miles Sabin - */ - trait IsComposite[P] extends Serializable { - type H - type T - - def head(p : P) : H - def tail(p : P) : T - } - - object IsComposite { - def apply[P](implicit isComp: IsComposite[P]): Aux[P, isComp.H, isComp.T] = isComp - - type Aux[P, H0, T0] = IsComposite[P] { type H = H0; type T = T0 } - - implicit def isComposite[P, L <: HList, H0, T <: HList] - (implicit gen: Generic.Aux[P, L], isHCons: hl.IsHCons.Aux[L, H0, T], tp: hl.Tupler[T]): Aux[P, H0, tp.Out] = - new IsComposite[P] { - type H = H0 - type T = tp.Out - def head(p: P): H = isHCons.head(gen.to(p)) - def tail(p: P): T = tp(isHCons.tail(gen.to(p))) - } - } - - /** - * Type class supporting prepending to this tuple. - * - * @author Miles Sabin - */ - trait Prepend[T, U] extends DepFn2[T, U] with Serializable - - object Prepend { - def apply[T, U](implicit prepend: Prepend[T, U]): Aux[T, U, prepend.Out] = prepend - - type Aux[T, U, Out0] = Prepend[T, U] { type Out = Out0 } - - implicit def prepend[T, L1 <: HList, U, L2 <: HList, L3 <: HList] - (implicit gent: Generic.Aux[T, L1], genu: Generic.Aux[U, L2], prepend: hl.Prepend.Aux[L1, L2, L3], tp: hl.Tupler[L3]): Aux[T, U, tp.Out] = - new Prepend[T, U] { - type Out = tp.Out - def apply(t: T, u: U): Out = prepend(gent.to(t), genu.to(u)).tupled - } - } - - /** - * Type class supporting reverse prepending to this tuple. - * - * @author Miles Sabin - */ - trait ReversePrepend[T, U] extends DepFn2[T, U] with Serializable - - object ReversePrepend { - def apply[T, U](implicit prepend: ReversePrepend[T, U]): Aux[T, U, prepend.Out] = prepend - - type Aux[T, U, Out0] = ReversePrepend[T, U] { type Out = Out0 } - - implicit def prepend[T, L1 <: HList, U, L2 <: HList, L3 <: HList] - (implicit gent: Generic.Aux[T, L1], genu: Generic.Aux[U, L2], prepend: hl.ReversePrepend.Aux[L1, L2, L3], tp: hl.Tupler[L3]): Aux[T, U, tp.Out] = - new ReversePrepend[T, U] { - type Out = tp.Out - def apply(t: T, u: U): Out = prepend(gent.to(t), genu.to(u)).tupled - } - } - - /** - * Type class supporting access to the ''nth'' element of this tuple. Available only if this tuple has at least - * ''n'' elements. - * - * @author Miles Sabin - */ - trait At[T, N <: Nat] extends DepFn1[T] with Serializable - - object At { - def apply[T, N <: Nat](implicit at: At[T, N]): Aux[T, N, at.Out] = at - - type Aux[T, N <: Nat, Out0] = At[T, N] { type Out = Out0 } - - implicit def at[T, L1 <: HList, N <: Nat] - (implicit gen: Generic.Aux[T, L1], at: hl.At[L1, N]): Aux[T, N, at.Out] = - new At[T, N] { - type Out = at.Out - def apply(t: T): Out = at(gen.to(t)) - } - } - - /** - * Type class supporting access to the last element of this tuple. Available only if this tuple has at least one - * element. - * - * @author Miles Sabin - */ - trait Last[T] extends DepFn1[T] with Serializable - - object Last { - def apply[T](implicit last: Last[T]): Aux[T, last.Out] = last - - type Aux[T, Out0] = Last[T] { type Out = Out0 } - - implicit def last[T, L <: HList] - (implicit gen: Generic.Aux[T, L], last: hl.Last[L]): Aux[T, last.Out] = - new Last[T] { - type Out = last.Out - def apply(t: T): Out = gen.to(t).last - } - } - - /** - * Type class supporting access to all but the last element of this tuple. Available only if this tuple has at - * least one element. - * - * @author Miles Sabin - */ - trait Init[T] extends DepFn1[T] with Serializable - - object Init { - def apply[T](implicit init: Init[T]): Aux[T, init.Out] = init - - type Aux[T, Out0] = Init[T] { type Out = Out0 } - - implicit def init[T, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], init: hl.Init.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = - new Init[T] { - type Out = tp.Out - def apply(t: T): Out = init(gen.to(t)).tupled - } - } - - /** - * Type class supporting access to the first element of this tuple of type `U`. Available only if this tuple - * contains an element of type `U`. - * - * @author Miles Sabin - */ - trait Selector[T, U] extends DepFn1[T] with Serializable { type Out = U } - - object Selector { - def apply[T, U](implicit selector: Selector[T, U]): Aux[T, U] = selector - - type Aux[T, U] = Selector[T, U] - - implicit def select[T, L <: HList, U] - (implicit gen: Generic.Aux[T, L], selector: hl.Selector[L, U]): Aux[T, U] = - new Selector[T, U] { - def apply(t: T): U = gen.to(t).select[U] - } - } - - /** - * Type class supporting access to the all elements of this tuple of type `U`. - * - * @author Miles Sabin - */ - trait Filter[T, U] extends DepFn1[T] with Serializable - - object Filter { - def apply[T, U](implicit filter: Filter[T, U]): Aux[T, U, filter.Out] = filter - - type Aux[T, U, Out0] = Filter[T, U] { type Out = Out0 } - - implicit def filterTuple[T, L1 <: HList, U, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], filter: hl.Filter.Aux[L1, U, L2], tp: hl.Tupler[L2]): Aux[T, U, tp.Out] = new Filter[T, U] { - type Out = tp.Out - def apply(t: T): Out = tp(filter(gen.to(t))) - } - } - - /** - * Type class supporting access to the all elements of this tuple of type different than `U`. - * - * @author Miles Sabin - */ - trait FilterNot[T, U] extends DepFn1[T] with Serializable - - object FilterNot { - def apply[T, U](implicit filter: FilterNot[T, U]): Aux[T, U, filter.Out] = filter - - type Aux[T, U, Out0] = FilterNot[T, U] { type Out = Out0 } - - implicit def filterNotTuple[T, L1 <: HList, U, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], filterNot: hl.FilterNot.Aux[L1, U, L2], tp: hl.Tupler[L2]): Aux[T, U, tp.Out] = new FilterNot[T, U] { - type Out = tp.Out - def apply(t: T): Out = tp(filterNot(gen.to(t))) - } - } - - /** - * Type class supporting removal of an element from this tuple. Available only if this tuple contains an - * element of type `U`. - * - * @author Miles Sabin - */ - trait Remove[T, U] extends DepFn1[T] with Serializable - - object Remove { - def apply[T, E](implicit remove: Remove[T, E]): Aux[T, E, remove.Out] = remove - - type Aux[T, U, Out0] = Remove[T, U] { type Out = Out0 } - - implicit def removeTuple[T, L1 <: HList, U, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], remove: hl.Remove.Aux[L1, U, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, (U, tp.Out)] = new Remove[T, U] { - type Out = (U, tp.Out) - def apply(t: T): Out = { val (u, rem) = remove(gen.to(t)) ; (u, tp(rem)) } - } - } - - /** - * Type class supporting removal of a sublist from this tuple. Available only if this tuple contains a - * sublist of type `SL`. - * - * The elements of `SL` do not have to be contiguous in this tuple. - * - * @author Miles Sabin - */ - trait RemoveAll[T, S] extends DepFn1[T] with Serializable - - object RemoveAll { - def apply[T, S](implicit remove: RemoveAll[T, S]): Aux[T, S, remove.Out] = remove - - type Aux[T, S, Out0] = RemoveAll[T, S] { type Out = Out0 } - - implicit def removeAllTuple[T, ST, SL <: HList, L1 <: HList, L2 <: HList] - (implicit gent: Generic.Aux[T, L1], gens: Generic.Aux[ST, SL], removeAll: hl.RemoveAll.Aux[L1, SL, (SL, L2)], tp: hl.Tupler[L2]): Aux[T, ST, (ST, tp.Out)] = - new RemoveAll[T, ST] { - type Out = (ST, tp.Out) - def apply(t: T): Out = { val (e, rem) = removeAll(gent.to(t)) ; (gens.from(e), tp(rem)) } - } - } - - /** - * Type class supporting replacement of the first element of type V from this tuple with an element of type U. - * Available only if this tuple contains an element of type `V`. - * - * @author Miles Sabin - */ - trait Replacer[T, U, V] extends DepFn2[T, V] with Serializable - - object Replacer { - def apply[T, U, V](implicit replacer: Replacer[T, U, V]): Aux[T, U, V, replacer.Out] = replacer - - type Aux[T, U, V, Out0] = Replacer[T, U, V] { type Out = Out0 } - - implicit def replaceTuple[T, L1 <: HList, U, V, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], replace: hl.Replacer.Aux[L1, U, V, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, V, (U, tp.Out)] = new Replacer[T, U, V] { - type Out = (U, tp.Out) - def apply(t: T, v: V): Out = { val (u, rep) = replace(gen.to(t), v) ; (u, tp(rep)) } - } - } - - /** - * Type class supporting replacement of the Nth element of this tuple with an element of type V. Available only if - * this tuple contains at least N elements. - * - * @author Miles Sabin - */ - trait ReplaceAt[T, N <: Nat, U] extends DepFn2[T, U] with Serializable - - object ReplaceAt { - def apply[T, N <: Nat, V](implicit replacer: ReplaceAt[T, N, V]): Aux[T, N, V, replacer.Out] = replacer - - type Aux[T, N <: Nat, U, Out0] = ReplaceAt[T, N, U] { type Out = Out0 } - - implicit def replaceTuple[T, L1 <: HList, N <: Nat, U, V, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], replaceAt: hl.ReplaceAt.Aux[L1, N, U, (V, L2)], tp: hl.Tupler[L2]): Aux[T, N, U, (V, tp.Out)] = new ReplaceAt[T, N, U] { - type Out = (V, tp.Out) - def apply(t: T, u: U): Out = { val (v, rep) = replaceAt(gen.to(t), u) ; (v, tp(rep)) } - } - } - - /** - * Type class supporting replacement of the first element of type U from this tuple with the result of - * its transformation via a given function into a new element of type V. - * Available only if this tuple contains an element of type `U`. - * - * @author Howard Branch - */ - trait Modifier[T, U, V] extends DepFn2[T, U => V] with Serializable - - object Modifier { - def apply[T, U, V](implicit modifier: Modifier[T, U, V]): Aux[T, U, V, modifier.Out] = modifier - - type Aux[T, U, V, Out0] = Modifier[T, U, V] { type Out = Out0 } - - implicit def modifyTuple[T, L1 <: HList, U, V, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], modify: hl.Modifier.Aux[L1, U, V, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, V, (U, tp.Out)] = new Modifier[T, U, V] { - type Out = (U, tp.Out) - def apply(t: T, f: U => V): Out = { val (u, rep) = modify(gen.to(t), f) ; (u, tp(rep)) } - } - } - - /** - * Type class supporting replacement of the `N`th element of this `Tuple` with the result of - * calling `F` on it. - * Available only if this `Tuple` contains at least `N` elements. - * - * @author Andreas Koestler - */ - trait ModifierAt[T, N <: Nat, U, V] extends DepFn2[T, U => V] - - object ModifierAt { - def apply[T, N <: Nat, U, V](implicit modifier: ModifierAt[T, N, U, V]): Aux[T, N, U, V, modifier.Out] = modifier - - type Aux[T, N <: Nat, U, V, Out0] = ModifierAt[T, N, U, V] {type Out = Out0} - - implicit def modifyTuple[S, T, U, V, N <: Nat, L <: HList, OutL <: HList] - (implicit - gen: Generic.Aux[T, L], - modifier: hl.ModifierAt.Aux[L, N, U, V, (S, OutL)], - tup: hl.Tupler[OutL] - ): Aux[T, N, U, V, (S, tup.Out)] = new ModifierAt[T, N, U, V] { - - type Out = (S, tup.Out) - - def apply(t: T, f: U => V) = { - val (u, rep) = modifier(gen.to(t), f); - (u, tup(rep)) - } - } - } - /** - * Type class supporting retrieval of the first ''n'' elements of this tuple. Available only if this tuple has at - * least ''n'' elements. - * - * @author Miles Sabin - */ - trait Take[T, N <: Nat] extends DepFn1[T] with Serializable - - object Take { - def apply[T, N <: Nat](implicit take: Take[T, N]): Aux[T, N, take.Out] = take - - type Aux[T, N <: Nat, Out0] = Take[T, N] { type Out = Out0 } - - implicit def tupleTake[T, L1 <: HList, N <: Nat, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], take: hl.Take.Aux[L1, N, L2], tp: hl.Tupler[L2]): Aux[T, N, tp.Out] = - new Take[T, N] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(take(gen.to(t))) - } - } - - /** - * Type class supporting removal of the first ''n'' elements of this tuple. Available only if this tuple has at - * least ''n'' elements. - * - * @author Miles Sabin - */ - trait Drop[T, N <: Nat] extends DepFn1[T] with Serializable - - object Drop { - def apply[T, N <: Nat](implicit drop: Drop[T, N]): Aux[T, N, drop.Out] = drop - - type Aux[T, N <: Nat, Out0] = Drop[T, N] { type Out = Out0 } - - implicit def tupleDrop[T, L1 <: HList, N <: Nat, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], drop: hl.Drop.Aux[L1, N, L2], tp: hl.Tupler[L2]): Aux[T, N, tp.Out] = - new Drop[T, N] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(drop(gen.to(t))) - } - } - - /** - * Type class supporting splitting this tuple at the ''nth'' element returning the prefix and suffix as a pair. - * Available only if this tuple has at least ''n'' elements. - * - * @author Miles Sabin - */ - trait Split[T, N <: Nat] extends DepFn1[T] with Serializable - - object Split { - def apply[T, N <: Nat](implicit split: Split[T, N]): Aux[T, N, split.Out] = split - - type Aux[T, N <: Nat, Out0] = Split[T, N] { type Out = Out0 } - - implicit def tupleSplit[T, L <: HList, N <: Nat, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.Split.Aux[L, N, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, N, (tpp.Out, tps.Out)] = - new Split[T, N] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting splitting this tuple at the ''nth'' element returning the reverse prefix and suffix as a - * pair. Available only if this tuple has at least ''n'' elements. - * - * @author Miles Sabin - */ - trait ReverseSplit[T, N <: Nat] extends DepFn1[T] with Serializable - - object ReverseSplit { - def apply[T, N <: Nat](implicit split: ReverseSplit[T, N]): Aux[T, N, split.Out] = split - - type Aux[T, N <: Nat, Out0] = ReverseSplit[T, N] { type Out = Out0 } - - implicit def tupleReverseSplit[T, L <: HList, N <: Nat, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.ReverseSplit.Aux[L, N, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, N, (tpp.Out, tps.Out)] = - new ReverseSplit[T, N] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting splitting this tuple at the first occurrence of an element of type `U` returning the prefix - * and suffix as a pair. Available only if this tuple contains an element of type `U`. - * - * @author Miles Sabin - */ - trait SplitLeft[T, U] extends DepFn1[T] with Serializable - - object SplitLeft { - def apply[T, U](implicit split: SplitLeft[T, U]): Aux[T, U, split.Out] = split - - type Aux[T, U, Out0] = SplitLeft[T, U] { type Out = Out0 } - - implicit def tupleSplitLeft[T, L <: HList, U, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.SplitLeft.Aux[L, U, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, U, (tpp.Out, tps.Out)] = - new SplitLeft[T, U] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting splitting this tuple at the first occurrence of an element of type `U` returning the reverse - * prefix and suffix as a pair. Available only if this tuple contains an element of type `U`. - * - * @author Miles Sabin - */ - trait ReverseSplitLeft[T, U] extends DepFn1[T] with Serializable - - object ReverseSplitLeft { - def apply[T, U](implicit split: ReverseSplitLeft[T, U]): Aux[T, U, split.Out] = split - - type Aux[T, U, Out0] = ReverseSplitLeft[T, U] { type Out = Out0 } - - implicit def tupleReverseSplitLeft[T, L <: HList, U, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.ReverseSplitLeft.Aux[L, U, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, U, (tpp.Out, tps.Out)] = - new ReverseSplitLeft[T, U] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting splitting this tuple at the last occurrence of an element of type `U` returning the prefix - * and suffix as a pair. Available only if this tuple contains an element of type `U`. - * - * @author Miles Sabin - */ - trait SplitRight[T, U] extends DepFn1[T] with Serializable - - object SplitRight { - def apply[T, U](implicit split: SplitRight[T, U]): Aux[T, U, split.Out] = split - - type Aux[T, U, Out0] = SplitRight[T, U] { type Out = Out0 } - - implicit def tupleSplitRight[T, L <: HList, U, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.SplitRight.Aux[L, U, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, U, (tpp.Out, tps.Out)] = - new SplitRight[T, U] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting splitting this tuple at the last occurrence of an element of type `U` returning the reverse - * prefix and suffix as a pair. Available only if this tuple contains an element of type `U`. - * - * @author Miles Sabin - */ - trait ReverseSplitRight[T, U] extends DepFn1[T] with Serializable - - object ReverseSplitRight { - def apply[T, U](implicit split: ReverseSplitRight[T, U]): Aux[T, U, split.Out] = split - - type Aux[T, U, Out0] = ReverseSplitRight[T, U] { type Out = Out0 } - - implicit def tupleReverseSplitRight[T, L <: HList, U, LP <: HList, LS <: HList] - (implicit - gen: Generic.Aux[T, L], - split: hl.ReverseSplitRight.Aux[L, U, LP, LS], - tpp: hl.Tupler[LP], - tps: hl.Tupler[LS] - ): Aux[T, U, (tpp.Out, tps.Out)] = - new ReverseSplitRight[T, U] { - type Out = (tpp.Out, tps.Out) - def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) ; (tpp(p), tps(s)) } - } - } - - /** - * Type class supporting reversing this tuple. - * - * @author Miles Sabin - */ - trait Reverse[T] extends DepFn1[T] with Serializable - - object Reverse { - def apply[T](implicit reverse: Reverse[T]): Aux[T, reverse.Out] = reverse - - type Aux[T, Out0] = Reverse[T] { type Out = Out0 } - - implicit def tupleReverseAux[T, L1 <: HList, L2 <: HList, Out] - (implicit gen: Generic.Aux[T, L1], reverse: hl.Reverse.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = - new Reverse[T] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(reverse(gen.to(t))) - } - } - - /** - * Type class supporting mapping a higher ranked function over this tuple. - * - * @author Miles Sabin - */ - trait Mapper[T, P] extends DepFn1[T] with Serializable - - object Mapper { - def apply[T, P](implicit mapper: Mapper[T, P]): Aux[T, P, mapper.Out] = mapper - - type Aux[T, P, Out0] = Mapper[T, P] { type Out = Out0 } - - implicit def mapper[T, P, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], mapper: hl.Mapper.Aux[P, L1, L2], tp: hl.Tupler[L2]): Aux[T, P, tp.Out] = - new Mapper[T, P] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(mapper(gen.to(t))) - } - } - - /** - * Type class supporting flatmapping a higher ranked function over this tuple. - * - * @author Miles Sabin - */ - trait FlatMapper[T, P] extends DepFn1[T] with Serializable - - object FlatMapper { - def apply[T, P](implicit mapper: FlatMapper[T, P]): Aux[T, P, mapper.Out] = mapper - - import poly.Compose - - type Aux[T, P, Out0] = FlatMapper[T, P] { type Out = Out0 } - - implicit def mapper[T, P, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], mapper: hl.FlatMapper.Aux[Compose[productElements.type, P], L1, L2], tp: hl.Tupler[L2]): Aux[T, P, tp.Out] = - new FlatMapper[T, P] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(mapper(gen.to(t))) - } - } - - /** - * Type class supporting mapping a constant valued function over this tuple. - * - * @author Miles Sabin - */ - trait ConstMapper[T, C] extends DepFn2[T, C] with Serializable - - object ConstMapper { - def apply[T, C](implicit mapper: ConstMapper[T, C]): Aux[T, C, mapper.Out] = mapper - - type Aux[T, C, Out0] = ConstMapper[T, C] { type Out = Out0 } - - implicit def mapper[T, C, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], mapper: hl.ConstMapper.Aux[C, L1, L2], tp: hl.Tupler[L2]): Aux[T, C, tp.Out] = - new ConstMapper[T, C] { - type Out = tp.Out - def apply(t: T, c: C): tp.Out = tp(mapper(c, gen.to(t))) - } - } - - /** - * Type class supporting mapping a polymorphic function over this tuple and then folding the result using a - * monomorphic function value. - * - * @author Miles Sabin - */ - trait MapFolder[T, R, P] extends Serializable { // Nb. Not a dependent function signature - def apply(t: T, in: R, op: (R, R) => R): R - } - - object MapFolder { - def apply[T, R, P](implicit folder: MapFolder[T, R, P]) = folder - - implicit def mapper[T, L <: HList, R, P] - (implicit gen: Generic.Aux[T, L], mapper: hl.MapFolder[L, R, P]): MapFolder[T, R, P] = - new MapFolder[T, R, P] { - def apply(t: T, in: R, op: (R, R) => R): R = mapper(gen.to(t), in, op) - } - } - - /** - * Type class supporting left-folding a polymorphic binary function over this tuple. - * - * @author Miles Sabin - */ - trait LeftFolder[T, U, P] extends DepFn2[T, U] with Serializable - - object LeftFolder { - def apply[T, U, P](implicit folder: LeftFolder[T, U, P]): Aux[T, U, P, folder.Out] = folder - - type Aux[T, U, P, Out0] = LeftFolder[T, U, P] { type Out = Out0 } - - implicit def folder[T, L <: HList, U, P] - (implicit gen: Generic.Aux[T, L], folder: hl.LeftFolder[L, U, P]): Aux[T, U, P, folder.Out] = - new LeftFolder[T, U, P] { - type Out = folder.Out - def apply(t: T, u: U): Out = folder(gen.to(t), u) - } - } - - /** - * Type class supporting right-folding a polymorphic binary function over this tuple. - * - * @author Miles Sabin - */ - trait RightFolder[T, U, P] extends DepFn2[T, U] with Serializable - - object RightFolder { - def apply[T, U, P](implicit folder: RightFolder[T, U, P]): Aux[T, U, P, folder.Out] = folder - - type Aux[T, U, P, Out0] = RightFolder[T, U, P] { type Out = Out0 } - - implicit def folder[T, L <: HList, U, P] - (implicit gen: Generic.Aux[T, L], folder: hl.RightFolder[L, U, P]): Aux[T, U, P, folder.Out] = - new RightFolder[T, U, P] { - type Out = folder.Out - def apply(t: T, u: U): Out = folder(gen.to(t), u) - } - } - - /** - * Type class supporting left-reducing a polymorphic binary function over this tuple. - * - * @author Miles Sabin - */ - trait LeftReducer[T, P] extends DepFn1[T] with Serializable - - object LeftReducer { - def apply[T, P](implicit reducer: LeftReducer[T, P]): Aux[T, P, reducer.Out] = reducer - - type Aux[T, P, Out0] = LeftReducer[T, P] { type Out = Out0 } - - implicit def folder[T, L <: HList, P] - (implicit gen: Generic.Aux[T, L], folder: hl.LeftReducer[L, P]): Aux[T, P, folder.Out] = - new LeftReducer[T, P] { - type Out = folder.Out - def apply(t: T): Out = folder(gen.to(t)) - } - } - - /** - * Type class supporting right-reducing a polymorphic binary function over this tuple. - * - * @author Miles Sabin - */ - trait RightReducer[T, P] extends DepFn1[T] with Serializable - - object RightReducer { - def apply[T, P](implicit reducer: RightReducer[T, P]): Aux[T, P, reducer.Out] = reducer - - type Aux[T, P, Out0] = RightReducer[T, P] { type Out = Out0 } - - implicit def folder[T, L <: HList, P] - (implicit gen: Generic.Aux[T, L], folder: hl.RightReducer[L, P]): Aux[T, P, folder.Out] = - new RightReducer[T, P] { - type Out = folder.Out - def apply(t: T): Out = folder(gen.to(t)) - } - } - - /** - * Type class supporting transposing this tuple. - * - * @author Miles Sabin - */ - trait Transposer[T] extends DepFn1[T] with Serializable - - object Transposer { - def apply[T](implicit transposer: Transposer[T]): Aux[T, transposer.Out] = transposer - - type Aux[T, Out0] = Transposer[T] { type Out = Out0 } - - implicit def transpose[T, L1 <: HList, L2 <: HList, L3 <: HList, L4 <: HList] - (implicit - gen: Generic.Aux[T, L1], - mpe: hl.Mapper.Aux[productElements.type, L1, L2], - tps: hl.Transposer.Aux[L2, L3], - mtp: hl.Mapper.Aux[tupled.type, L3, L4], - tp: hl.Tupler[L4] - ): Aux[T, tp.Out] = - new Transposer[T] { - type Out = tp.Out - def apply(t: T): Out = ((gen.to(t) map productElements).transpose map tupled).tupled - } - } - - /** - * Type class supporting zipping this this tuple of monomorphic function values with its argument tuple of - * correspondingly typed function arguments returning the result of each application as a tuple. Available only if - * there is evidence that the corresponding function and argument elements have compatible types. - * - * @author Miles Sabin - */ - trait ZipApply[FT, AT] extends DepFn2[FT, AT] with Serializable - - object ZipApply { - def apply[FT, AT](implicit zip: ZipApply[FT, AT]): Aux[FT, AT, zip.Out] = zip - - type Aux[FT, AT, Out0] = ZipApply[FT, AT] { type Out = Out0 } - - implicit def zipApply[FT, FL <: HList, AT, AL <: HList, RL <: HList] - (implicit - genf: Generic.Aux[FT, FL], - gena: Generic.Aux[AT, AL], - zip: hl.ZipApply.Aux[FL, AL, RL], - tp: hl.Tupler[RL] - ): Aux[FT, AT, tp.Out] = - new ZipApply[FT, AT] { - type Out = tp.Out - def apply(ft: FT, at: AT): Out = (genf.to(ft) zipApply gena.to(at)).tupled - } - } - - /** - * Type class supporting zipping this tuple with a tuple of tuples returning a tuple of tuples with each - * element of this tuple prepended to the corresponding tuple element of the argument tuple. - * - * @author Miles Sabin - */ - trait ZipOne[H, T] extends DepFn2[H, T] with Serializable - - object ZipOne { - def apply[H, T](implicit zip: ZipOne[H, T]): Aux[H, T, zip.Out] = zip - - type Aux[H, T, Out0] = ZipOne[H, T] { type Out = Out0 } - - implicit def zipOne[HT, HL <: HList, TT, TL <: HList, TLL <: HList, RLL <: HList, RL <: HList] - (implicit - genh: Generic.Aux[HT, HL], - gent: Generic.Aux[TT, TL], - mpet: hl.Mapper.Aux[productElements.type, TL, TLL], - zone: hl.ZipOne.Aux[HL, TLL, RLL], - mtp: hl.Mapper.Aux[tupled.type, RLL, RL], - tp: hl.Tupler[RL] - ): Aux[HT, TT, tp.Out] = - new ZipOne[HT, TT] { - type Out = tp.Out - def apply(h: HT, t: TT): Out = ((genh.to(h) zipOne (gent.to(t) map productElements)) map tupled).tupled - } - } - - /** - * Type class supporting zipping a tuple with a constant, resulting in a tuple of tuples of the form - * ({element from input tuple}, {supplied constant}) - * - * @author Miles Sabin - */ - trait ZipConst[T, C] extends DepFn2[T, C] with Serializable - - object ZipConst { - def apply[T, C](implicit zip: ZipConst[T, C]): Aux[T, C, zip.Out] = zip - - type Aux[T, C, Out0] = ZipConst[T, C] { type Out = Out0 } - - implicit def zipConst[T, C, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], zipper: hl.ZipConst.Aux[C, L1, L2], tp: hl.Tupler[L2]): Aux[T, C, tp.Out] = - new ZipConst[T, C] { - type Out = tp.Out - def apply(t: T, c: C): tp.Out = tp(zipper(c, gen.to(t))) - } - } - - /** - * Type class supporting zipping a tuple with its element indices, resulting in a tuple of tuples of the form - * ({element from input tuple}, {element index}) - * - * @author Andreas Koestler - */ - trait ZipWithIndex[T] extends DepFn1[T] with Serializable - - object ZipWithIndex { - def apply[T](implicit zip: ZipWithIndex[T]): Aux[T, zip.Out] = zip - - type Aux[T, Out0] = ZipWithIndex[T] { type Out = Out0 } - - implicit def zipConst[T, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], zipper: hl.ZipWithIndex.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = - new ZipWithIndex[T] { - type Out = tp.Out - def apply(t: T): tp.Out = tp(zipper(gen.to(t))) - } - } - - - /** - * Type class supporting unification of this tuple. - * - * @author Miles Sabin - */ - trait Unifier[T] extends DepFn1[T] with Serializable - - object Unifier { - def apply[T](implicit unifier: Unifier[T]): Aux[T, unifier.Out] = unifier - - type Aux[T, Out0] = Unifier[T] { type Out = Out0 } - - implicit def unifier[T, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], unifier: hl.Unifier.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = - new Unifier[T] { - type Out = tp.Out - def apply(t: T): Out = unifier(gen.to(t)).tupled - } - } - - /** - * Type class supporting unification of all elements that are subtypes of `B` in this tuple to `B`, with all other - * elements left unchanged. - * - * @author Miles Sabin - */ - trait SubtypeUnifier[T, B] extends DepFn1[T] with Serializable - - object SubtypeUnifier { - def apply[T, B](implicit unifier: SubtypeUnifier[T, B]): Aux[T, B, unifier.Out] = unifier - - type Aux[T, B, Out0] = SubtypeUnifier[T, B] { type Out = Out0 } - - implicit def subtypeUnifier[T, B, L1 <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L1], unifier: hl.SubtypeUnifier.Aux[L1, B, L2], tp: hl.Tupler[L2]): Aux[T, B, tp.Out] = - new SubtypeUnifier[T, B] { - type Out = tp.Out - def apply(t: T): Out = unifier(gen.to(t)).tupled - } - } - - /** - * Type class supporting computing the type-level Nat corresponding to the length of this tuple. - * - * @author Miles Sabin - */ - trait Length[T] extends DepFn1[T] with Serializable - - object Length { - def apply[T](implicit length: Length[T]): Aux[T, length.Out] = length - - type Aux[T, Out0] = Length[T] { type Out = Out0 } - - implicit def length[T, L <: HList] - (implicit gen: Generic.Aux[T, L], length: hl.Length[L]): Aux[T, length.Out] = - new Length[T] { - type Out = length.Out - def apply(t: T): Out = length() - } - } - - /** - * Type class supporting conversion of this tuple to a `M` with elements typed as the least upper bound - * of the types of the elements of this tuple. - * - * @author Alexandre Archambault - */ - trait ToTraversable[T, M[_]] extends DepFn1[T] with Serializable { - type Lub - type Out = M[Lub] - } - - object ToTraversable { - def apply[T, M[_]] - (implicit toTraversable: ToTraversable[T, M]): Aux[T, M, toTraversable.Lub] = toTraversable - - type Aux[T, M[_], Lub0] = ToTraversable[T, M] { type Lub = Lub0 } - - implicit def toTraversableNothing[M[_]](implicit tt: hl.ToTraversable.Aux[HNil, M, Nothing]): Aux[Unit, M, Nothing] = - new ToTraversable[Unit, M] { - type Lub = Nothing - def apply(t: Unit) = tt(HNil) - } - - implicit def toTraversable[T, L <: HList, M[_], Lub] - (implicit gen: Generic.Aux[T, L], toTraversable: hl.ToTraversable.Aux[L, M, Lub]): Aux[T, M, Lub] = - new ToTraversable[T, M] { - type Lub = toTraversable.Lub - def apply(t: T) = gen.to(t).to[M] - } - } - - /** - * Type class supporting conversion of this tuple to a `List` with elements typed as the least upper bound - * of the types of the elements of this tuple. - * - * Provided for backward compatibility. - * - * @author Miles Sabin - */ - trait ToList[T, Lub] extends DepFn1[T] with Serializable - - object ToList { - type Aux[T, Lub, Out0] = ToList[T, Lub] { type Out = Out0 } - - def apply[T, Lub](implicit toList: ToList[T, Lub]): Aux[T, Lub, toList.Out] = toList - - implicit def toList[T, Lub] - (implicit toTraversable: ToTraversable.Aux[T, List, Lub]): Aux[T, Lub, List[Lub]] = - new ToList[T, Lub] { - type Out = List[Lub] - def apply(t: T) = toTraversable(t) - } - - implicit def toListNothing[T] - (implicit toTraversable: ToTraversable.Aux[T, List, Nothing]): Aux[T, Nothing, List[Nothing]] = - toList[T, Nothing] - } - - /** - * Type class supporting conversion of this tuple to an `Array` with elements typed as the least upper bound - * of the types of the elements of this tuple. - * - * Provided for backward compatibility. - * - * @author Miles Sabin - */ - trait ToArray[T, Lub] extends DepFn1[T] - - object ToArray { - type Aux[T, Lub, Out0] = ToArray[T, Lub] { type Out = Out0 } - - def apply[T, Lub](implicit toArray: ToArray[T, Lub]): Aux[T, Lub, toArray.Out] = toArray - - implicit def toArray[T, Lub] - (implicit toTraversable: ToTraversable.Aux[T, Array, Lub]): Aux[T, Lub, Array[Lub]] = - new ToArray[T, Lub] { - type Out = Array[Lub] - def apply(t: T) = toTraversable(t) - } - - implicit def toArrayNothing[T] - (implicit toTraversable: ToTraversable.Aux[T, Array, Nothing]): Aux[T, Nothing, Array[Nothing]] = - toArray[T, Nothing] - } - - /** - * Type class supporting conversion of this tuple to a `Sized[M[Lub], N]` with elements typed as - * the least upper bound Lub of the types of the elements of this tuple. - * - * @author Alexandre Archambault - */ - trait ToSized[T, M[_]] extends DepFn1[T] with Serializable - - object ToSized { - def apply[T, M[_]](implicit toSized: ToSized[T, M]): Aux[T, M, toSized.Out] = toSized - - type Aux[T, M[_], Out0] = ToSized[T, M] { type Out = Out0 } - - implicit def toSized[T, L <: HList, M[_]] - (implicit gen: Generic.Aux[T, L], toSized: hl.ToSized[L, M]): Aux[T, M, toSized.Out] = - new ToSized[T, M] { - type Out = toSized.Out - def apply(t: T) = gen.to(t).toSized[M] - } - } - - /** - * Type class computing the coproduct type corresponding to this tuple. - * - * @author Andreas Koestler - */ - trait ToCoproduct[T] extends Serializable { type Out <: Coproduct } - - object ToCoproduct { - def apply[T](implicit tcp: ToCoproduct[T]): Aux[T, tcp.Out] = tcp - - type Aux[T, Out0 <: Coproduct] = ToCoproduct[T] {type Out = Out0} - - implicit val hnilToCoproduct: Aux[HNil, CNil] = - new ToCoproduct[HNil] { - type Out = CNil - } - - implicit def hlistToCoproduct[T, L <: HList](implicit - gen: Generic.Aux[T, L], - ut: hl.ToCoproduct[L] - ): Aux[T, ut.Out] = - new ToCoproduct[T] { - type Out = ut.Out - } - } - - /** - * Type class computing the sum type corresponding to this tuple. - * - * @author Andreas Koestler - */ - trait ToSum[T] extends Serializable { type Out <: Coproduct } - - object ToSum { - def apply[T](implicit tcp: ToSum[T]): Aux[T, tcp.Out] = tcp - - type Aux[T, Out0 <: Coproduct] = ToSum[T] {type Out = Out0} - - implicit val hnilToSum: Aux[HNil, CNil] = - new ToSum[HNil] { - type Out = CNil - } - - implicit def hlistToSum[T, L <: HList](implicit - gen: Generic.Aux[T, L], - ut: hl.ToSum[L] - ): Aux[T, ut.Out] = - new ToSum[T] { - type Out = ut.Out - } - } - - - /** - * Type Class witnessing that this tuple can be collected with a 'Poly' to produce a new tuple - * - * @author Stacy Curl - */ - trait Collect[T, P <: Poly] extends DepFn1[T] with Serializable - - object Collect { - def apply[T, P <: Poly](implicit collect: Collect[T, P]): Aux[T, P, collect.Out] = collect - - type Aux[T, P <: Poly, Out0] = Collect[T, P] { type Out = Out0 } - - implicit def collect[T, L <: HList, L2 <: HList, P <: Poly] - (implicit gen: Generic.Aux[T, L], collect: hl.Collect.Aux[L, P, L2], tp: hl.Tupler[L2]) - : Aux[T, P, tp.Out] = new Collect[T, P] { - type Out = tp.Out - - def apply(t: T): tp.Out = tp(collect(gen.to(t))) - } - } - - /** - * Typer class supporting the calculation of every permutation of this tuple - * - * @author Stacy Curl - */ - trait Permutations[T] extends DepFn1[T] with Serializable - - object Permutations { - def apply[T](implicit permutations: Permutations[T]): Aux[T, permutations.Out] = permutations - - type Aux[T, Out0] = Permutations[T] { type Out = Out0 } - - implicit def permutations[T, L <: HList, L2 <: HList, L3 <: HList] - (implicit gen: Generic.Aux[T, L], collect: hl.Permutations.Aux[L, L2], - mapper: hl.Mapper.Aux[tupled.type, L2, L3], tp: hl.Tupler[L3] - ): Aux[T, tp.Out] = new Permutations[T] { - type Out = tp.Out - - def apply(t: T): Out = tp(collect(gen.to(t)).map(tupled)) - } - } - - /** - * Type class supporting rotating a tuple left - * - * @author Stacy Curl - */ - trait RotateLeft[T, N <: Nat] extends DepFn1[T] with Serializable - - object RotateLeft { - def apply[T, N <: Nat](implicit rotateLeft: RotateLeft[T, N]): Aux[T, N, rotateLeft.Out] = rotateLeft - - type Aux[T, N <: Nat, Out0] = RotateLeft[T, N] { type Out = Out0 } - - implicit def tupleRotateLeft[T, N <: Nat, L <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L], rotateLeft: hl.RotateLeft.Aux[L, N, L2], tp: hl.Tupler[L2]) - : Aux[T, N, tp.Out] = new RotateLeft[T, N] { - type Out = tp.Out - - def apply(t: T): Out = tp(rotateLeft(gen.to(t))) - } - } - - /** - * Type class supporting rotating a tuple right - * - * @author Stacy Curl - */ - trait RotateRight[T, N <: Nat] extends DepFn1[T] with Serializable - - object RotateRight { - def apply[T, N <: Nat](implicit rotateRight: RotateRight[T, N]): Aux[T, N, rotateRight.Out] = rotateRight - - type Aux[T, N <: Nat, Out0] = RotateRight[T, N] { type Out = Out0 } - - implicit def tupleRotateRight[T, N <: Nat, L <: HList, L2 <: HList] - (implicit gen: Generic.Aux[T, L], rotateRight: hl.RotateRight.Aux[L, N, L2], tp: hl.Tupler[L2]) - : Aux[T, N, tp.Out] = new RotateRight[T, N] { - type Out = tp.Out - - def apply(t: T): Out = tp(rotateRight(gen.to(t))) - } - } - - /** - * Type class supporting left-scanning a binary polymorphic function over this tuple. - * - * @author Owein Reese - */ - trait LeftScanner[T, In, P <: Poly] extends DepFn2[T, In] with Serializable - - object LeftScanner{ - def apply[T, In, P <: Poly](implicit scanL: LeftScanner[T, In, P]): Aux[T, In, P, scanL.Out] = scanL - - type Aux[T, In, P <: Poly, Out0] = LeftScanner[T, In, P] { type Out = Out0 } - - implicit def scanner[T, L <: HList, In, P <: Poly, R <: HList] - (implicit gen: Generic.Aux[T, L], - scanL: hl.LeftScanner.Aux[L, In, P, R], - tp: hl.Tupler[R] - ): Aux[T, In, P, tp.Out] = - new LeftScanner[T, In, P] { - type Out = tp.Out - - def apply(t: T, in: In): Out = tp(scanL(gen.to(t), in)) - } - } - - /** - * Type class supporting right-scanning a binary polymorphic function over this tuple. - * - * @author Owein Reese - */ - trait RightScanner[T, In, P <: Poly] extends DepFn2[T, In] with Serializable - - object RightScanner{ - def apply[T, In, P <: Poly](implicit scanR: RightScanner[T, In, P]): Aux[T, In, P, scanR.Out] = scanR - - type Aux[T, In, P <: Poly, Out0] = RightScanner[T, In, P] { type Out = Out0 } - - implicit def scanner[T, L <: HList, In, P <: Poly, R <: HList] - (implicit gen: Generic.Aux[T, L], - scanR: hl.RightScanner.Aux[L, In, P, R], - tp: hl.Tupler[R] - ): Aux[T, In, P, tp.Out] = - new RightScanner[T, In, P] { - type Out = tp.Out - - def apply(t: T, in: In): Out = tp(scanR(gen.to(t), in)) - } - } - - /** - * Type class supporting producing a tuple of shape `N` filled with elements of type `A`. - * - * @author Alexandre Archambault - */ - trait Fill[N, A] extends DepFn1[A] with Serializable - - object Fill { - def apply[N, A](implicit fill: Fill[N, A]) = fill - - type Aux[N, A, Out0] = Fill[N, A] { type Out = Out0 } - - implicit def fill1[N <: Nat, A, L <: HList, P] - (implicit fill: hlist.Fill.Aux[N, A, L], tupler: hlist.Tupler[L]): Aux[N, A, tupler.Out] = - new Fill[N, A] { - type Out = tupler.Out - def apply(elem: A) = tupler(fill(elem)) - } - - implicit def fill2[A, N1 <: Nat, N2 <: Nat, SubOut] - (implicit subFill: Fill.Aux[N2, A, SubOut], fill: Fill[N1, SubOut]): Aux[(N1, N2), A, fill.Out] = - new Fill[(N1, N2), A] { - type Out = fill.Out - def apply(elem: A) = fill(subFill(elem)) - } - - } - - /** - * Type class supporting the patching of a tuple. - * - * @author Owein Reese - */ - trait Patcher[N <: Nat, M <: Nat, T, InT] extends DepFn2[T, InT] with Serializable - - object Patcher{ - def apply[N <: Nat, M <: Nat, T, InT](implicit patch: Patcher[N, M, T, InT]) = patch - - implicit def tuplePatch[N <: Nat, M <: Nat, T, L <: HList, InT, InL <: HList, OutL <: HList] - (implicit gen: Generic.Aux[T, L], - genIn: Generic.Aux[InT, InL], - patch: hl.Patcher.Aux[N, M, L, InL, OutL], - tp: hl.Tupler[OutL]): Patcher[N, M, T, InT] { - type Out = tp.Out - } = - new Patcher[N, M, T, InT]{ - type Out = tp.Out - - def apply(t: T, in: InT) = tp(patch(gen.to(t), genIn.to(in))) - } - } - - /** - * Typeclass supporting grouping this `Tuple` into tuples of `N` items each, at `Step` - * apart. If `Step` equals `N` then the groups do not overlap. - * - * @author Andreas Koestler - */ - trait Grouper[T, N <: Nat, Step <: Nat] extends DepFn1[T] with Serializable - - object Grouper { - def apply[T, N <: Nat, Step <: Nat](implicit grouper: Grouper[T, N, Step]): Aux[T, N, Step, grouper.Out] = grouper - - type Aux[T, N <: Nat, Step <: Nat, Out0] = Grouper[T, N, Step] {type Out = Out0} - - implicit def tupleGrouper[T, N <: Nat, Step <: Nat, L <: HList, OutL <: HList] - (implicit - gen: Generic.Aux[T, L], - grouper: hl.Grouper.Aux[L, N, Step, OutL], - tupler: hl.Tupler[OutL] - ): Aux[T, N, Step, tupler.Out] = new Grouper[T, N, Step] { - type Out = tupler.Out - - def apply(t: T): Out = tupler(grouper(gen.to(t))) - } - - } - - /** - * Typeclass supporting grouping this `Tuple` into tuples of `N` items each, at `Step` - * apart. If `Step` equals `N` then the groups do not overlap. - * - * Use the elements in `Pad` as necessary to complete last partition - * up to `n` items. In case there are not enough padding elements, return a partition - * with less than `n` items. - * - * @author Andreas Koestler - */ - trait PaddedGrouper[T, N <: Nat, Step <: Nat, Pad] extends DepFn2[T, Pad] with Serializable - - object PaddedGrouper { - def apply[T, N <: Nat, Step <: Nat, Pad](implicit - grouper: PaddedGrouper[T, N, Step, Pad] - ): Aux[T, N, Step, Pad, grouper.Out] = grouper - - type Aux[T, N <: Nat, Step <: Nat, Pad, Out0] = PaddedGrouper[T, N, Step, Pad] {type Out = Out0} - - implicit def tuplePaddedGrouper[Pad, PadL <: HList, T, N <: Nat, Step <: Nat, L <: HList, OutL <: HList] - (implicit - genL: Generic.Aux[T, L], - genPad: Generic.Aux[Pad, PadL], - grouper: hl.PaddedGrouper.Aux[L, N, Step, PadL, OutL], - tupler: hl.Tupler[OutL] - ): Aux[T, N, Step, Pad, tupler.Out] = new PaddedGrouper[T, N, Step, Pad] { - type Out = tupler.Out - - def apply(t: T, pad: Pad): Out = tupler(grouper(genL.to(t), genPad.to(pad))) - } - - } - - /** - * Type class supporting permuting this `Tuple` into the same order as another `Tuple` with - * the same element types. - * - * @author Peter Neyens - */ - @implicitNotFound("Implicit not found: shapeless.ops.tuple.Align[${T}, ${U}]. The types ${T} and ${U} cannot be aligned.") - trait Align[T, U] extends (T => U) with Serializable { - def apply(t: T): U - } - - object Align { - def apply[T, U](implicit align: Align[T, U]): Align[T, U] = align - - implicit def tupleAlign[T, U, L <: HList, M <: HList] - (implicit - gent: Generic.Aux[T, L], - genu: Generic.Aux[U, M], - align: hl.Align[L, M], - tp: hl.Tupler.Aux[M, U] - ): Align[T, U] = - new Align[T, U] { - def apply(t: T): U = align(gent.to(t)).tupled - } - } +/* + * Copyright (c) 2013-15 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops + +import scala.annotation.implicitNotFound + +object tuple { + import shapeless.ops.{ hlist => hl } + + /** + * Type class witnessing that this tuple is composite and providing access to head and tail. + * + * @author Miles Sabin + */ + trait IsComposite[P] extends Serializable { + type H + type T + + def head(p : P) : H + def tail(p : P) : T + } + + object IsComposite { + def apply[P](implicit isComp: IsComposite[P]): Aux[P, isComp.H, isComp.T] = isComp + + type Aux[P, H0, T0] = IsComposite[P] { type H = H0; type T = T0 } + + implicit def isComposite[P, L <: HList, H0, T <: HList] + (implicit gen: Generic.Aux[P, L], isHCons: hl.IsHCons.Aux[L, H0, T], tp: hl.Tupler[T]): Aux[P, H0, tp.Out] = + new IsComposite[P] { + type H = H0 + type T = tp.Out + def head(p: P): H = isHCons.head(gen.to(p)) + def tail(p: P): T = tp(isHCons.tail(gen.to(p))) + } + } + + /** + * Type class supporting prepending to this tuple. + * + * @author Miles Sabin + */ + trait Prepend[T, U] extends DepFn2[T, U] with Serializable + + object Prepend { + def apply[T, U](implicit prepend: Prepend[T, U]): Aux[T, U, prepend.Out] = prepend + + type Aux[T, U, Out0] = Prepend[T, U] { type Out = Out0 } + + implicit def prepend[T, L1 <: HList, U, L2 <: HList, L3 <: HList] + (implicit gent: Generic.Aux[T, L1], genu: Generic.Aux[U, L2], prepend: hl.Prepend.Aux[L1, L2, L3], tp: hl.Tupler[L3]): Aux[T, U, tp.Out] = + new Prepend[T, U] { + type Out = tp.Out + def apply(t: T, u: U): Out = prepend(gent.to(t), genu.to(u)).tupled + } + } + + /** + * Type class supporting reverse prepending to this tuple. + * + * @author Miles Sabin + */ + trait ReversePrepend[T, U] extends DepFn2[T, U] with Serializable + + object ReversePrepend { + def apply[T, U](implicit prepend: ReversePrepend[T, U]): Aux[T, U, prepend.Out] = prepend + + type Aux[T, U, Out0] = ReversePrepend[T, U] { type Out = Out0 } + + implicit def prepend[T, L1 <: HList, U, L2 <: HList, L3 <: HList] + (implicit gent: Generic.Aux[T, L1], genu: Generic.Aux[U, L2], prepend: hl.ReversePrepend.Aux[L1, L2, L3], tp: hl.Tupler[L3]): Aux[T, U, tp.Out] = + new ReversePrepend[T, U] { + type Out = tp.Out + def apply(t: T, u: U): Out = prepend(gent.to(t), genu.to(u)).tupled + } + } + + /** + * Type class supporting access to the ''nth'' element of this tuple. Available only if this tuple has at least + * ''n'' elements. + * + * @author Miles Sabin + */ + trait At[T, N <: Nat] extends DepFn1[T] with Serializable + + object At { + def apply[T, N <: Nat](implicit at: At[T, N]): Aux[T, N, at.Out] = at + + type Aux[T, N <: Nat, Out0] = At[T, N] { type Out = Out0 } + + implicit def at[T, L1 <: HList, N <: Nat] + (implicit gen: Generic.Aux[T, L1], at: hl.At[L1, N]): Aux[T, N, at.Out] = + new At[T, N] { + type Out = at.Out + def apply(t: T): Out = at(gen.to(t)) + } + } + + /** + * Type class supporting access to the last element of this tuple. Available only if this tuple has at least one + * element. + * + * @author Miles Sabin + */ + trait Last[T] extends DepFn1[T] with Serializable + + object Last { + def apply[T](implicit last: Last[T]): Aux[T, last.Out] = last + + type Aux[T, Out0] = Last[T] { type Out = Out0 } + + implicit def last[T, L <: HList] + (implicit gen: Generic.Aux[T, L], last: hl.Last[L]): Aux[T, last.Out] = + new Last[T] { + type Out = last.Out + def apply(t: T): Out = gen.to(t).last + } + } + + /** + * Type class supporting access to all but the last element of this tuple. Available only if this tuple has at + * least one element. + * + * @author Miles Sabin + */ + trait Init[T] extends DepFn1[T] with Serializable + + object Init { + def apply[T](implicit init: Init[T]): Aux[T, init.Out] = init + + type Aux[T, Out0] = Init[T] { type Out = Out0 } + + implicit def init[T, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], init: hl.Init.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = + new Init[T] { + type Out = tp.Out + def apply(t: T): Out = init(gen.to(t)).tupled + } + } + + /** + * Type class supporting access to the first element of this tuple of type `U`. Available only if this tuple + * contains an element of type `U`. + * + * @author Miles Sabin + */ + trait Selector[T, U] extends DepFn1[T] with Serializable { type Out = U } + + object Selector { + def apply[T, U](implicit selector: Selector[T, U]): Aux[T, U] = selector + + type Aux[T, U] = Selector[T, U] + + implicit def select[T, L <: HList, U] + (implicit gen: Generic.Aux[T, L], selector: hl.Selector[L, U]): Aux[T, U] = + new Selector[T, U] { + def apply(t: T): U = gen.to(t).select[U] + } + } + + /** + * Type class supporting access to the all elements of this tuple of type `U`. + * + * @author Miles Sabin + */ + trait Filter[T, U] extends DepFn1[T] with Serializable + + object Filter { + def apply[T, U](implicit filter: Filter[T, U]): Aux[T, U, filter.Out] = filter + + type Aux[T, U, Out0] = Filter[T, U] { type Out = Out0 } + + implicit def filterTuple[T, L1 <: HList, U, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], filter: hl.Filter.Aux[L1, U, L2], tp: hl.Tupler[L2]): Aux[T, U, tp.Out] = new Filter[T, U] { + type Out = tp.Out + def apply(t: T): Out = tp(filter(gen.to(t))) + } + } + + /** + * Type class supporting access to the all elements of this tuple of type different than `U`. + * + * @author Miles Sabin + */ + trait FilterNot[T, U] extends DepFn1[T] with Serializable + + object FilterNot { + def apply[T, U](implicit filter: FilterNot[T, U]): Aux[T, U, filter.Out] = filter + + type Aux[T, U, Out0] = FilterNot[T, U] { type Out = Out0 } + + implicit def filterNotTuple[T, L1 <: HList, U, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], filterNot: hl.FilterNot.Aux[L1, U, L2], tp: hl.Tupler[L2]): Aux[T, U, tp.Out] = new FilterNot[T, U] { + type Out = tp.Out + def apply(t: T): Out = tp(filterNot(gen.to(t))) + } + } + + /** + * Type class supporting removal of an element from this tuple. Available only if this tuple contains an + * element of type `U`. + * + * @author Miles Sabin + */ + trait Remove[T, U] extends DepFn1[T] with Serializable + + object Remove { + def apply[T, E](implicit remove: Remove[T, E]): Aux[T, E, remove.Out] = remove + + type Aux[T, U, Out0] = Remove[T, U] { type Out = Out0 } + + implicit def removeTuple[T, L1 <: HList, U, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], remove: hl.Remove.Aux[L1, U, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, (U, tp.Out)] = new Remove[T, U] { + type Out = (U, tp.Out) + def apply(t: T): Out = { val (u, rem) = remove(gen.to(t)) ; (u, tp(rem)) } + } + } + + /** + * Type class supporting removal of a sublist from this tuple. Available only if this tuple contains a + * sublist of type `SL`. + * + * The elements of `SL` do not have to be contiguous in this tuple. + * + * @author Miles Sabin + */ + trait RemoveAll[T, S] extends DepFn1[T] with Serializable + + object RemoveAll { + def apply[T, S](implicit remove: RemoveAll[T, S]): Aux[T, S, remove.Out] = remove + + type Aux[T, S, Out0] = RemoveAll[T, S] { type Out = Out0 } + + implicit def removeAllTuple[T, ST, SL <: HList, L1 <: HList, L2 <: HList] + (implicit gent: Generic.Aux[T, L1], gens: Generic.Aux[ST, SL], removeAll: hl.RemoveAll.Aux[L1, SL, (SL, L2)], tp: hl.Tupler[L2]): Aux[T, ST, (ST, tp.Out)] = + new RemoveAll[T, ST] { + type Out = (ST, tp.Out) + def apply(t: T): Out = { val (e, rem) = removeAll(gent.to(t)) ; (gens.from(e), tp(rem)) } + } + } + + /** + * Type class supporting replacement of the first element of type V from this tuple with an element of type U. + * Available only if this tuple contains an element of type `V`. + * + * @author Miles Sabin + */ + trait Replacer[T, U, V] extends DepFn2[T, V] with Serializable + + object Replacer { + def apply[T, U, V](implicit replacer: Replacer[T, U, V]): Aux[T, U, V, replacer.Out] = replacer + + type Aux[T, U, V, Out0] = Replacer[T, U, V] { type Out = Out0 } + + implicit def replaceTuple[T, L1 <: HList, U, V, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], replace: hl.Replacer.Aux[L1, U, V, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, V, (U, tp.Out)] = new Replacer[T, U, V] { + type Out = (U, tp.Out) + def apply(t: T, v: V): Out = { val (u, rep) = replace(gen.to(t), v) ; (u, tp(rep)) } + } + } + + /** + * Type class supporting replacement of the Nth element of this tuple with an element of type V. Available only if + * this tuple contains at least N elements. + * + * @author Miles Sabin + */ + trait ReplaceAt[T, N <: Nat, U] extends DepFn2[T, U] with Serializable + + object ReplaceAt { + def apply[T, N <: Nat, V](implicit replacer: ReplaceAt[T, N, V]): Aux[T, N, V, replacer.Out] = replacer + + type Aux[T, N <: Nat, U, Out0] = ReplaceAt[T, N, U] { type Out = Out0 } + + implicit def replaceTuple[T, L1 <: HList, N <: Nat, U, V, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], replaceAt: hl.ReplaceAt.Aux[L1, N, U, (V, L2)], tp: hl.Tupler[L2]): Aux[T, N, U, (V, tp.Out)] = new ReplaceAt[T, N, U] { + type Out = (V, tp.Out) + def apply(t: T, u: U): Out = { val (v, rep) = replaceAt(gen.to(t), u) ; (v, tp(rep)) } + } + } + + /** + * Type class supporting replacement of the first element of type U from this tuple with the result of + * its transformation via a given function into a new element of type V. + * Available only if this tuple contains an element of type `U`. + * + * @author Howard Branch + */ + trait Modifier[T, U, V] extends DepFn2[T, U => V] with Serializable + + object Modifier { + def apply[T, U, V](implicit modifier: Modifier[T, U, V]): Aux[T, U, V, modifier.Out] = modifier + + type Aux[T, U, V, Out0] = Modifier[T, U, V] { type Out = Out0 } + + implicit def modifyTuple[T, L1 <: HList, U, V, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], modify: hl.Modifier.Aux[L1, U, V, (U, L2)], tp: hl.Tupler[L2]): Aux[T, U, V, (U, tp.Out)] = new Modifier[T, U, V] { + type Out = (U, tp.Out) + def apply(t: T, f: U => V): Out = { val (u, rep) = modify(gen.to(t), f) ; (u, tp(rep)) } + } + } + + /** + * Type class supporting replacement of the `N`th element of this `Tuple` with the result of + * calling `F` on it. + * Available only if this `Tuple` contains at least `N` elements. + * + * @author Andreas Koestler + */ + trait ModifierAt[T, N <: Nat, U, V] extends DepFn2[T, U => V] + + object ModifierAt { + def apply[T, N <: Nat, U, V](implicit modifier: ModifierAt[T, N, U, V]): Aux[T, N, U, V, modifier.Out] = modifier + + type Aux[T, N <: Nat, U, V, Out0] = ModifierAt[T, N, U, V] {type Out = Out0} + + implicit def modifyTuple[S, T, U, V, N <: Nat, L <: HList, OutL <: HList] + (implicit + gen: Generic.Aux[T, L], + modifier: hl.ModifierAt.Aux[L, N, U, V, (S, OutL)], + tup: hl.Tupler[OutL] + ): Aux[T, N, U, V, (S, tup.Out)] = new ModifierAt[T, N, U, V] { + + type Out = (S, tup.Out) + + def apply(t: T, f: U => V) = { + val (u, rep) = modifier(gen.to(t), f); + (u, tup(rep)) + } + } + } + /** + * Type class supporting retrieval of the first ''n'' elements of this tuple. Available only if this tuple has at + * least ''n'' elements. + * + * @author Miles Sabin + */ + trait Take[T, N <: Nat] extends DepFn1[T] with Serializable + + object Take { + def apply[T, N <: Nat](implicit take: Take[T, N]): Aux[T, N, take.Out] = take + + type Aux[T, N <: Nat, Out0] = Take[T, N] { type Out = Out0 } + + implicit def tupleTake[T, L1 <: HList, N <: Nat, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], take: hl.Take.Aux[L1, N, L2], tp: hl.Tupler[L2]): Aux[T, N, tp.Out] = + new Take[T, N] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(take(gen.to(t))) + } + } + + /** + * Type class supporting removal of the first ''n'' elements of this tuple. Available only if this tuple has at + * least ''n'' elements. + * + * @author Miles Sabin + */ + trait Drop[T, N <: Nat] extends DepFn1[T] with Serializable + + object Drop { + def apply[T, N <: Nat](implicit drop: Drop[T, N]): Aux[T, N, drop.Out] = drop + + type Aux[T, N <: Nat, Out0] = Drop[T, N] { type Out = Out0 } + + implicit def tupleDrop[T, L1 <: HList, N <: Nat, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], drop: hl.Drop.Aux[L1, N, L2], tp: hl.Tupler[L2]): Aux[T, N, tp.Out] = + new Drop[T, N] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(drop(gen.to(t))) + } + } + + /** + * Type class supporting splitting this tuple at the ''nth'' element returning the prefix and suffix as a pair. + * Available only if this tuple has at least ''n'' elements. + * + * @author Miles Sabin + */ + trait Split[T, N <: Nat] extends DepFn1[T] with Serializable + + object Split { + def apply[T, N <: Nat](implicit split: Split[T, N]): Aux[T, N, split.Out] = split + + type Aux[T, N <: Nat, Out0] = Split[T, N] { type Out = Out0 } + + implicit def tupleSplit[T, L <: HList, N <: Nat, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.Split.Aux[L, N, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, N, (tpp.Out, tps.Out)] = + new Split[T, N] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting splitting this tuple at the ''nth'' element returning the reverse prefix and suffix as a + * pair. Available only if this tuple has at least ''n'' elements. + * + * @author Miles Sabin + */ + trait ReverseSplit[T, N <: Nat] extends DepFn1[T] with Serializable + + object ReverseSplit { + def apply[T, N <: Nat](implicit split: ReverseSplit[T, N]): Aux[T, N, split.Out] = split + + type Aux[T, N <: Nat, Out0] = ReverseSplit[T, N] { type Out = Out0 } + + implicit def tupleReverseSplit[T, L <: HList, N <: Nat, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.ReverseSplit.Aux[L, N, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, N, (tpp.Out, tps.Out)] = + new ReverseSplit[T, N] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting splitting this tuple at the first occurrence of an element of type `U` returning the prefix + * and suffix as a pair. Available only if this tuple contains an element of type `U`. + * + * @author Miles Sabin + */ + trait SplitLeft[T, U] extends DepFn1[T] with Serializable + + object SplitLeft { + def apply[T, U](implicit split: SplitLeft[T, U]): Aux[T, U, split.Out] = split + + type Aux[T, U, Out0] = SplitLeft[T, U] { type Out = Out0 } + + implicit def tupleSplitLeft[T, L <: HList, U, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.SplitLeft.Aux[L, U, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, U, (tpp.Out, tps.Out)] = + new SplitLeft[T, U] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting splitting this tuple at the first occurrence of an element of type `U` returning the reverse + * prefix and suffix as a pair. Available only if this tuple contains an element of type `U`. + * + * @author Miles Sabin + */ + trait ReverseSplitLeft[T, U] extends DepFn1[T] with Serializable + + object ReverseSplitLeft { + def apply[T, U](implicit split: ReverseSplitLeft[T, U]): Aux[T, U, split.Out] = split + + type Aux[T, U, Out0] = ReverseSplitLeft[T, U] { type Out = Out0 } + + implicit def tupleReverseSplitLeft[T, L <: HList, U, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.ReverseSplitLeft.Aux[L, U, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, U, (tpp.Out, tps.Out)] = + new ReverseSplitLeft[T, U] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting splitting this tuple at the last occurrence of an element of type `U` returning the prefix + * and suffix as a pair. Available only if this tuple contains an element of type `U`. + * + * @author Miles Sabin + */ + trait SplitRight[T, U] extends DepFn1[T] with Serializable + + object SplitRight { + def apply[T, U](implicit split: SplitRight[T, U]): Aux[T, U, split.Out] = split + + type Aux[T, U, Out0] = SplitRight[T, U] { type Out = Out0 } + + implicit def tupleSplitRight[T, L <: HList, U, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.SplitRight.Aux[L, U, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, U, (tpp.Out, tps.Out)] = + new SplitRight[T, U] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting splitting this tuple at the last occurrence of an element of type `U` returning the reverse + * prefix and suffix as a pair. Available only if this tuple contains an element of type `U`. + * + * @author Miles Sabin + */ + trait ReverseSplitRight[T, U] extends DepFn1[T] with Serializable + + object ReverseSplitRight { + def apply[T, U](implicit split: ReverseSplitRight[T, U]): Aux[T, U, split.Out] = split + + type Aux[T, U, Out0] = ReverseSplitRight[T, U] { type Out = Out0 } + + implicit def tupleReverseSplitRight[T, L <: HList, U, LP <: HList, LS <: HList] + (implicit + gen: Generic.Aux[T, L], + split: hl.ReverseSplitRight.Aux[L, U, LP, LS], + tpp: hl.Tupler[LP], + tps: hl.Tupler[LS] + ): Aux[T, U, (tpp.Out, tps.Out)] = + new ReverseSplitRight[T, U] { + type Out = (tpp.Out, tps.Out) + def apply(t: T): Out = { val p :: s :: HNil = split.product(gen.to(t)) : @unchecked ; (tpp(p), tps(s)) } + } + } + + /** + * Type class supporting reversing this tuple. + * + * @author Miles Sabin + */ + trait Reverse[T] extends DepFn1[T] with Serializable + + object Reverse { + def apply[T](implicit reverse: Reverse[T]): Aux[T, reverse.Out] = reverse + + type Aux[T, Out0] = Reverse[T] { type Out = Out0 } + + implicit def tupleReverseAux[T, L1 <: HList, L2 <: HList, Out] + (implicit gen: Generic.Aux[T, L1], reverse: hl.Reverse.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = + new Reverse[T] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(reverse(gen.to(t))) + } + } + + /** + * Type class supporting mapping a higher ranked function over this tuple. + * + * @author Miles Sabin + */ + trait Mapper[T, P] extends DepFn1[T] with Serializable + + object Mapper { + def apply[T, P](implicit mapper: Mapper[T, P]): Aux[T, P, mapper.Out] = mapper + + type Aux[T, P, Out0] = Mapper[T, P] { type Out = Out0 } + + implicit def mapper[T, P, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], mapper: hl.Mapper.Aux[P, L1, L2], tp: hl.Tupler[L2]): Aux[T, P, tp.Out] = + new Mapper[T, P] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(mapper(gen.to(t))) + } + } + + /** + * Type class supporting flatmapping a higher ranked function over this tuple. + * + * @author Miles Sabin + */ + trait FlatMapper[T, P] extends DepFn1[T] with Serializable + + object FlatMapper { + def apply[T, P](implicit mapper: FlatMapper[T, P]): Aux[T, P, mapper.Out] = mapper + + import poly.Compose + + type Aux[T, P, Out0] = FlatMapper[T, P] { type Out = Out0 } + + implicit def mapper[T, P, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], mapper: hl.FlatMapper.Aux[Compose[productElements.type, P], L1, L2], tp: hl.Tupler[L2]): Aux[T, P, tp.Out] = + new FlatMapper[T, P] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(mapper(gen.to(t))) + } + } + + /** + * Type class supporting mapping a constant valued function over this tuple. + * + * @author Miles Sabin + */ + trait ConstMapper[T, C] extends DepFn2[T, C] with Serializable + + object ConstMapper { + def apply[T, C](implicit mapper: ConstMapper[T, C]): Aux[T, C, mapper.Out] = mapper + + type Aux[T, C, Out0] = ConstMapper[T, C] { type Out = Out0 } + + implicit def mapper[T, C, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], mapper: hl.ConstMapper.Aux[C, L1, L2], tp: hl.Tupler[L2]): Aux[T, C, tp.Out] = + new ConstMapper[T, C] { + type Out = tp.Out + def apply(t: T, c: C): tp.Out = tp(mapper(c, gen.to(t))) + } + } + + /** + * Type class supporting mapping a polymorphic function over this tuple and then folding the result using a + * monomorphic function value. + * + * @author Miles Sabin + */ + trait MapFolder[T, R, P] extends Serializable { // Nb. Not a dependent function signature + def apply(t: T, in: R, op: (R, R) => R): R + } + + object MapFolder { + def apply[T, R, P](implicit folder: MapFolder[T, R, P]) = folder + + implicit def mapper[T, L <: HList, R, P] + (implicit gen: Generic.Aux[T, L], mapper: hl.MapFolder[L, R, P]): MapFolder[T, R, P] = + new MapFolder[T, R, P] { + def apply(t: T, in: R, op: (R, R) => R): R = mapper(gen.to(t), in, op) + } + } + + /** + * Type class supporting left-folding a polymorphic binary function over this tuple. + * + * @author Miles Sabin + */ + trait LeftFolder[T, U, P] extends DepFn2[T, U] with Serializable + + object LeftFolder { + def apply[T, U, P](implicit folder: LeftFolder[T, U, P]): Aux[T, U, P, folder.Out] = folder + + type Aux[T, U, P, Out0] = LeftFolder[T, U, P] { type Out = Out0 } + + implicit def folder[T, L <: HList, U, P] + (implicit gen: Generic.Aux[T, L], folder: hl.LeftFolder[L, U, P]): Aux[T, U, P, folder.Out] = + new LeftFolder[T, U, P] { + type Out = folder.Out + def apply(t: T, u: U): Out = folder(gen.to(t), u) + } + } + + /** + * Type class supporting right-folding a polymorphic binary function over this tuple. + * + * @author Miles Sabin + */ + trait RightFolder[T, U, P] extends DepFn2[T, U] with Serializable + + object RightFolder { + def apply[T, U, P](implicit folder: RightFolder[T, U, P]): Aux[T, U, P, folder.Out] = folder + + type Aux[T, U, P, Out0] = RightFolder[T, U, P] { type Out = Out0 } + + implicit def folder[T, L <: HList, U, P] + (implicit gen: Generic.Aux[T, L], folder: hl.RightFolder[L, U, P]): Aux[T, U, P, folder.Out] = + new RightFolder[T, U, P] { + type Out = folder.Out + def apply(t: T, u: U): Out = folder(gen.to(t), u) + } + } + + /** + * Type class supporting left-reducing a polymorphic binary function over this tuple. + * + * @author Miles Sabin + */ + trait LeftReducer[T, P] extends DepFn1[T] with Serializable + + object LeftReducer { + def apply[T, P](implicit reducer: LeftReducer[T, P]): Aux[T, P, reducer.Out] = reducer + + type Aux[T, P, Out0] = LeftReducer[T, P] { type Out = Out0 } + + implicit def folder[T, L <: HList, P] + (implicit gen: Generic.Aux[T, L], folder: hl.LeftReducer[L, P]): Aux[T, P, folder.Out] = + new LeftReducer[T, P] { + type Out = folder.Out + def apply(t: T): Out = folder(gen.to(t)) + } + } + + /** + * Type class supporting right-reducing a polymorphic binary function over this tuple. + * + * @author Miles Sabin + */ + trait RightReducer[T, P] extends DepFn1[T] with Serializable + + object RightReducer { + def apply[T, P](implicit reducer: RightReducer[T, P]): Aux[T, P, reducer.Out] = reducer + + type Aux[T, P, Out0] = RightReducer[T, P] { type Out = Out0 } + + implicit def folder[T, L <: HList, P] + (implicit gen: Generic.Aux[T, L], folder: hl.RightReducer[L, P]): Aux[T, P, folder.Out] = + new RightReducer[T, P] { + type Out = folder.Out + def apply(t: T): Out = folder(gen.to(t)) + } + } + + /** + * Type class supporting transposing this tuple. + * + * @author Miles Sabin + */ + trait Transposer[T] extends DepFn1[T] with Serializable + + object Transposer { + def apply[T](implicit transposer: Transposer[T]): Aux[T, transposer.Out] = transposer + + type Aux[T, Out0] = Transposer[T] { type Out = Out0 } + + implicit def transpose[T, L1 <: HList, L2 <: HList, L3 <: HList, L4 <: HList] + (implicit + gen: Generic.Aux[T, L1], + mpe: hl.Mapper.Aux[productElements.type, L1, L2], + tps: hl.Transposer.Aux[L2, L3], + mtp: hl.Mapper.Aux[tupled.type, L3, L4], + tp: hl.Tupler[L4] + ): Aux[T, tp.Out] = + new Transposer[T] { + type Out = tp.Out + def apply(t: T): Out = ((gen.to(t) map productElements).transpose map tupled).tupled + } + } + + /** + * Type class supporting zipping this this tuple of monomorphic function values with its argument tuple of + * correspondingly typed function arguments returning the result of each application as a tuple. Available only if + * there is evidence that the corresponding function and argument elements have compatible types. + * + * @author Miles Sabin + */ + trait ZipApply[FT, AT] extends DepFn2[FT, AT] with Serializable + + object ZipApply { + def apply[FT, AT](implicit zip: ZipApply[FT, AT]): Aux[FT, AT, zip.Out] = zip + + type Aux[FT, AT, Out0] = ZipApply[FT, AT] { type Out = Out0 } + + implicit def zipApply[FT, FL <: HList, AT, AL <: HList, RL <: HList] + (implicit + genf: Generic.Aux[FT, FL], + gena: Generic.Aux[AT, AL], + zip: hl.ZipApply.Aux[FL, AL, RL], + tp: hl.Tupler[RL] + ): Aux[FT, AT, tp.Out] = + new ZipApply[FT, AT] { + type Out = tp.Out + def apply(ft: FT, at: AT): Out = (genf.to(ft) zipApply gena.to(at)).tupled + } + } + + /** + * Type class supporting zipping this tuple with a tuple of tuples returning a tuple of tuples with each + * element of this tuple prepended to the corresponding tuple element of the argument tuple. + * + * @author Miles Sabin + */ + trait ZipOne[H, T] extends DepFn2[H, T] with Serializable + + object ZipOne { + def apply[H, T](implicit zip: ZipOne[H, T]): Aux[H, T, zip.Out] = zip + + type Aux[H, T, Out0] = ZipOne[H, T] { type Out = Out0 } + + implicit def zipOne[HT, HL <: HList, TT, TL <: HList, TLL <: HList, RLL <: HList, RL <: HList] + (implicit + genh: Generic.Aux[HT, HL], + gent: Generic.Aux[TT, TL], + mpet: hl.Mapper.Aux[productElements.type, TL, TLL], + zone: hl.ZipOne.Aux[HL, TLL, RLL], + mtp: hl.Mapper.Aux[tupled.type, RLL, RL], + tp: hl.Tupler[RL] + ): Aux[HT, TT, tp.Out] = + new ZipOne[HT, TT] { + type Out = tp.Out + def apply(h: HT, t: TT): Out = ((genh.to(h) zipOne (gent.to(t) map productElements)) map tupled).tupled + } + } + + /** + * Type class supporting zipping a tuple with a constant, resulting in a tuple of tuples of the form + * ({element from input tuple}, {supplied constant}) + * + * @author Miles Sabin + */ + trait ZipConst[T, C] extends DepFn2[T, C] with Serializable + + object ZipConst { + def apply[T, C](implicit zip: ZipConst[T, C]): Aux[T, C, zip.Out] = zip + + type Aux[T, C, Out0] = ZipConst[T, C] { type Out = Out0 } + + implicit def zipConst[T, C, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], zipper: hl.ZipConst.Aux[C, L1, L2], tp: hl.Tupler[L2]): Aux[T, C, tp.Out] = + new ZipConst[T, C] { + type Out = tp.Out + def apply(t: T, c: C): tp.Out = tp(zipper(c, gen.to(t))) + } + } + + /** + * Type class supporting zipping a tuple with its element indices, resulting in a tuple of tuples of the form + * ({element from input tuple}, {element index}) + * + * @author Andreas Koestler + */ + trait ZipWithIndex[T] extends DepFn1[T] with Serializable + + object ZipWithIndex { + def apply[T](implicit zip: ZipWithIndex[T]): Aux[T, zip.Out] = zip + + type Aux[T, Out0] = ZipWithIndex[T] { type Out = Out0 } + + implicit def zipConst[T, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], zipper: hl.ZipWithIndex.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = + new ZipWithIndex[T] { + type Out = tp.Out + def apply(t: T): tp.Out = tp(zipper(gen.to(t))) + } + } + + + /** + * Type class supporting unification of this tuple. + * + * @author Miles Sabin + */ + trait Unifier[T] extends DepFn1[T] with Serializable + + object Unifier { + def apply[T](implicit unifier: Unifier[T]): Aux[T, unifier.Out] = unifier + + type Aux[T, Out0] = Unifier[T] { type Out = Out0 } + + implicit def unifier[T, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], unifier: hl.Unifier.Aux[L1, L2], tp: hl.Tupler[L2]): Aux[T, tp.Out] = + new Unifier[T] { + type Out = tp.Out + def apply(t: T): Out = unifier(gen.to(t)).tupled + } + } + + /** + * Type class supporting unification of all elements that are subtypes of `B` in this tuple to `B`, with all other + * elements left unchanged. + * + * @author Miles Sabin + */ + trait SubtypeUnifier[T, B] extends DepFn1[T] with Serializable + + object SubtypeUnifier { + def apply[T, B](implicit unifier: SubtypeUnifier[T, B]): Aux[T, B, unifier.Out] = unifier + + type Aux[T, B, Out0] = SubtypeUnifier[T, B] { type Out = Out0 } + + implicit def subtypeUnifier[T, B, L1 <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L1], unifier: hl.SubtypeUnifier.Aux[L1, B, L2], tp: hl.Tupler[L2]): Aux[T, B, tp.Out] = + new SubtypeUnifier[T, B] { + type Out = tp.Out + def apply(t: T): Out = unifier(gen.to(t)).tupled + } + } + + /** + * Type class supporting computing the type-level Nat corresponding to the length of this tuple. + * + * @author Miles Sabin + */ + trait Length[T] extends DepFn1[T] with Serializable + + object Length { + def apply[T](implicit length: Length[T]): Aux[T, length.Out] = length + + type Aux[T, Out0] = Length[T] { type Out = Out0 } + + implicit def length[T, L <: HList] + (implicit gen: Generic.Aux[T, L], length: hl.Length[L]): Aux[T, length.Out] = + new Length[T] { + type Out = length.Out + def apply(t: T): Out = length() + } + } + + /** + * Type class supporting conversion of this tuple to a `M` with elements typed as the least upper bound + * of the types of the elements of this tuple. + * + * @author Alexandre Archambault + */ + trait ToTraversable[T, M[_]] extends DepFn1[T] with Serializable { + type Lub + type Out = M[Lub] + } + + object ToTraversable { + def apply[T, M[_]] + (implicit toTraversable: ToTraversable[T, M]): Aux[T, M, toTraversable.Lub] = toTraversable + + type Aux[T, M[_], Lub0] = ToTraversable[T, M] { type Lub = Lub0 } + + implicit def toTraversableNothing[M[_]](implicit tt: hl.ToTraversable.Aux[HNil, M, Nothing]): Aux[Unit, M, Nothing] = + new ToTraversable[Unit, M] { + type Lub = Nothing + def apply(t: Unit) = tt(HNil) + } + + implicit def toTraversable[T, L <: HList, M[_], Lub] + (implicit gen: Generic.Aux[T, L], toTraversable: hl.ToTraversable.Aux[L, M, Lub]): Aux[T, M, Lub] = + new ToTraversable[T, M] { + type Lub = toTraversable.Lub + def apply(t: T) = gen.to(t).to[M] + } + } + + /** + * Type class supporting conversion of this tuple to a `List` with elements typed as the least upper bound + * of the types of the elements of this tuple. + * + * Provided for backward compatibility. + * + * @author Miles Sabin + */ + trait ToList[T, Lub] extends DepFn1[T] with Serializable + + object ToList { + type Aux[T, Lub, Out0] = ToList[T, Lub] { type Out = Out0 } + + def apply[T, Lub](implicit toList: ToList[T, Lub]): Aux[T, Lub, toList.Out] = toList + + implicit def toList[T, Lub] + (implicit toTraversable: ToTraversable.Aux[T, List, Lub]): Aux[T, Lub, List[Lub]] = + new ToList[T, Lub] { + type Out = List[Lub] + def apply(t: T) = toTraversable(t) + } + + implicit def toListNothing[T] + (implicit toTraversable: ToTraversable.Aux[T, List, Nothing]): Aux[T, Nothing, List[Nothing]] = + toList[T, Nothing] + } + + /** + * Type class supporting conversion of this tuple to an `Array` with elements typed as the least upper bound + * of the types of the elements of this tuple. + * + * Provided for backward compatibility. + * + * @author Miles Sabin + */ + trait ToArray[T, Lub] extends DepFn1[T] + + object ToArray { + type Aux[T, Lub, Out0] = ToArray[T, Lub] { type Out = Out0 } + + def apply[T, Lub](implicit toArray: ToArray[T, Lub]): Aux[T, Lub, toArray.Out] = toArray + + implicit def toArray[T, Lub] + (implicit toTraversable: ToTraversable.Aux[T, Array, Lub]): Aux[T, Lub, Array[Lub]] = + new ToArray[T, Lub] { + type Out = Array[Lub] + def apply(t: T) = toTraversable(t) + } + + implicit def toArrayNothing[T] + (implicit toTraversable: ToTraversable.Aux[T, Array, Nothing]): Aux[T, Nothing, Array[Nothing]] = + toArray[T, Nothing] + } + + /** + * Type class supporting conversion of this tuple to a `Sized[M[Lub], N]` with elements typed as + * the least upper bound Lub of the types of the elements of this tuple. + * + * @author Alexandre Archambault + */ + trait ToSized[T, M[_]] extends DepFn1[T] with Serializable + + object ToSized { + def apply[T, M[_]](implicit toSized: ToSized[T, M]): Aux[T, M, toSized.Out] = toSized + + type Aux[T, M[_], Out0] = ToSized[T, M] { type Out = Out0 } + + implicit def toSized[T, L <: HList, M[_]] + (implicit gen: Generic.Aux[T, L], toSized: hl.ToSized[L, M]): Aux[T, M, toSized.Out] = + new ToSized[T, M] { + type Out = toSized.Out + def apply(t: T) = gen.to(t).toSized[M] + } + } + + /** + * Type class computing the coproduct type corresponding to this tuple. + * + * @author Andreas Koestler + */ + trait ToCoproduct[T] extends Serializable { type Out <: Coproduct } + + object ToCoproduct { + def apply[T](implicit tcp: ToCoproduct[T]): Aux[T, tcp.Out] = tcp + + type Aux[T, Out0 <: Coproduct] = ToCoproduct[T] {type Out = Out0} + + implicit val hnilToCoproduct: Aux[HNil, CNil] = + new ToCoproduct[HNil] { + type Out = CNil + } + + implicit def hlistToCoproduct[T, L <: HList](implicit + gen: Generic.Aux[T, L], + ut: hl.ToCoproduct[L] + ): Aux[T, ut.Out] = + new ToCoproduct[T] { + type Out = ut.Out + } + } + + /** + * Type class computing the sum type corresponding to this tuple. + * + * @author Andreas Koestler + */ + trait ToSum[T] extends Serializable { type Out <: Coproduct } + + object ToSum { + def apply[T](implicit tcp: ToSum[T]): Aux[T, tcp.Out] = tcp + + type Aux[T, Out0 <: Coproduct] = ToSum[T] {type Out = Out0} + + implicit val hnilToSum: Aux[HNil, CNil] = + new ToSum[HNil] { + type Out = CNil + } + + implicit def hlistToSum[T, L <: HList](implicit + gen: Generic.Aux[T, L], + ut: hl.ToSum[L] + ): Aux[T, ut.Out] = + new ToSum[T] { + type Out = ut.Out + } + } + + + /** + * Type Class witnessing that this tuple can be collected with a 'Poly' to produce a new tuple + * + * @author Stacy Curl + */ + trait Collect[T, P <: Poly] extends DepFn1[T] with Serializable + + object Collect { + def apply[T, P <: Poly](implicit collect: Collect[T, P]): Aux[T, P, collect.Out] = collect + + type Aux[T, P <: Poly, Out0] = Collect[T, P] { type Out = Out0 } + + implicit def collect[T, L <: HList, L2 <: HList, P <: Poly] + (implicit gen: Generic.Aux[T, L], collect: hl.Collect.Aux[L, P, L2], tp: hl.Tupler[L2]) + : Aux[T, P, tp.Out] = new Collect[T, P] { + type Out = tp.Out + + def apply(t: T): tp.Out = tp(collect(gen.to(t))) + } + } + + /** + * Typer class supporting the calculation of every permutation of this tuple + * + * @author Stacy Curl + */ + trait Permutations[T] extends DepFn1[T] with Serializable + + object Permutations { + def apply[T](implicit permutations: Permutations[T]): Aux[T, permutations.Out] = permutations + + type Aux[T, Out0] = Permutations[T] { type Out = Out0 } + + implicit def permutations[T, L <: HList, L2 <: HList, L3 <: HList] + (implicit gen: Generic.Aux[T, L], collect: hl.Permutations.Aux[L, L2], + mapper: hl.Mapper.Aux[tupled.type, L2, L3], tp: hl.Tupler[L3] + ): Aux[T, tp.Out] = new Permutations[T] { + type Out = tp.Out + + def apply(t: T): Out = tp(collect(gen.to(t)).map(tupled)) + } + } + + /** + * Type class supporting rotating a tuple left + * + * @author Stacy Curl + */ + trait RotateLeft[T, N <: Nat] extends DepFn1[T] with Serializable + + object RotateLeft { + def apply[T, N <: Nat](implicit rotateLeft: RotateLeft[T, N]): Aux[T, N, rotateLeft.Out] = rotateLeft + + type Aux[T, N <: Nat, Out0] = RotateLeft[T, N] { type Out = Out0 } + + implicit def tupleRotateLeft[T, N <: Nat, L <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L], rotateLeft: hl.RotateLeft.Aux[L, N, L2], tp: hl.Tupler[L2]) + : Aux[T, N, tp.Out] = new RotateLeft[T, N] { + type Out = tp.Out + + def apply(t: T): Out = tp(rotateLeft(gen.to(t))) + } + } + + /** + * Type class supporting rotating a tuple right + * + * @author Stacy Curl + */ + trait RotateRight[T, N <: Nat] extends DepFn1[T] with Serializable + + object RotateRight { + def apply[T, N <: Nat](implicit rotateRight: RotateRight[T, N]): Aux[T, N, rotateRight.Out] = rotateRight + + type Aux[T, N <: Nat, Out0] = RotateRight[T, N] { type Out = Out0 } + + implicit def tupleRotateRight[T, N <: Nat, L <: HList, L2 <: HList] + (implicit gen: Generic.Aux[T, L], rotateRight: hl.RotateRight.Aux[L, N, L2], tp: hl.Tupler[L2]) + : Aux[T, N, tp.Out] = new RotateRight[T, N] { + type Out = tp.Out + + def apply(t: T): Out = tp(rotateRight(gen.to(t))) + } + } + + /** + * Type class supporting left-scanning a binary polymorphic function over this tuple. + * + * @author Owein Reese + */ + trait LeftScanner[T, In, P <: Poly] extends DepFn2[T, In] with Serializable + + object LeftScanner{ + def apply[T, In, P <: Poly](implicit scanL: LeftScanner[T, In, P]): Aux[T, In, P, scanL.Out] = scanL + + type Aux[T, In, P <: Poly, Out0] = LeftScanner[T, In, P] { type Out = Out0 } + + implicit def scanner[T, L <: HList, In, P <: Poly, R <: HList] + (implicit gen: Generic.Aux[T, L], + scanL: hl.LeftScanner.Aux[L, In, P, R], + tp: hl.Tupler[R] + ): Aux[T, In, P, tp.Out] = + new LeftScanner[T, In, P] { + type Out = tp.Out + + def apply(t: T, in: In): Out = tp(scanL(gen.to(t), in)) + } + } + + /** + * Type class supporting right-scanning a binary polymorphic function over this tuple. + * + * @author Owein Reese + */ + trait RightScanner[T, In, P <: Poly] extends DepFn2[T, In] with Serializable + + object RightScanner{ + def apply[T, In, P <: Poly](implicit scanR: RightScanner[T, In, P]): Aux[T, In, P, scanR.Out] = scanR + + type Aux[T, In, P <: Poly, Out0] = RightScanner[T, In, P] { type Out = Out0 } + + implicit def scanner[T, L <: HList, In, P <: Poly, R <: HList] + (implicit gen: Generic.Aux[T, L], + scanR: hl.RightScanner.Aux[L, In, P, R], + tp: hl.Tupler[R] + ): Aux[T, In, P, tp.Out] = + new RightScanner[T, In, P] { + type Out = tp.Out + + def apply(t: T, in: In): Out = tp(scanR(gen.to(t), in)) + } + } + + /** + * Type class supporting producing a tuple of shape `N` filled with elements of type `A`. + * + * @author Alexandre Archambault + */ + trait Fill[N, A] extends DepFn1[A] with Serializable + + object Fill { + def apply[N, A](implicit fill: Fill[N, A]) = fill + + type Aux[N, A, Out0] = Fill[N, A] { type Out = Out0 } + + implicit def fill1[N <: Nat, A, L <: HList, P] + (implicit fill: hlist.Fill.Aux[N, A, L], tupler: hlist.Tupler[L]): Aux[N, A, tupler.Out] = + new Fill[N, A] { + type Out = tupler.Out + def apply(elem: A) = tupler(fill(elem)) + } + + implicit def fill2[A, N1 <: Nat, N2 <: Nat, SubOut] + (implicit subFill: Fill.Aux[N2, A, SubOut], fill: Fill[N1, SubOut]): Aux[(N1, N2), A, fill.Out] = + new Fill[(N1, N2), A] { + type Out = fill.Out + def apply(elem: A) = fill(subFill(elem)) + } + + } + + /** + * Type class supporting the patching of a tuple. + * + * @author Owein Reese + */ + trait Patcher[N <: Nat, M <: Nat, T, InT] extends DepFn2[T, InT] with Serializable + + object Patcher{ + def apply[N <: Nat, M <: Nat, T, InT](implicit patch: Patcher[N, M, T, InT]) = patch + + implicit def tuplePatch[N <: Nat, M <: Nat, T, L <: HList, InT, InL <: HList, OutL <: HList] + (implicit gen: Generic.Aux[T, L], + genIn: Generic.Aux[InT, InL], + patch: hl.Patcher.Aux[N, M, L, InL, OutL], + tp: hl.Tupler[OutL]): Patcher[N, M, T, InT] { + type Out = tp.Out + } = + new Patcher[N, M, T, InT]{ + type Out = tp.Out + + def apply(t: T, in: InT) = tp(patch(gen.to(t), genIn.to(in))) + } + } + + /** + * Typeclass supporting grouping this `Tuple` into tuples of `N` items each, at `Step` + * apart. If `Step` equals `N` then the groups do not overlap. + * + * @author Andreas Koestler + */ + trait Grouper[T, N <: Nat, Step <: Nat] extends DepFn1[T] with Serializable + + object Grouper { + def apply[T, N <: Nat, Step <: Nat](implicit grouper: Grouper[T, N, Step]): Aux[T, N, Step, grouper.Out] = grouper + + type Aux[T, N <: Nat, Step <: Nat, Out0] = Grouper[T, N, Step] {type Out = Out0} + + implicit def tupleGrouper[T, N <: Nat, Step <: Nat, L <: HList, OutL <: HList] + (implicit + gen: Generic.Aux[T, L], + grouper: hl.Grouper.Aux[L, N, Step, OutL], + tupler: hl.Tupler[OutL] + ): Aux[T, N, Step, tupler.Out] = new Grouper[T, N, Step] { + type Out = tupler.Out + + def apply(t: T): Out = tupler(grouper(gen.to(t))) + } + + } + + /** + * Typeclass supporting grouping this `Tuple` into tuples of `N` items each, at `Step` + * apart. If `Step` equals `N` then the groups do not overlap. + * + * Use the elements in `Pad` as necessary to complete last partition + * up to `n` items. In case there are not enough padding elements, return a partition + * with less than `n` items. + * + * @author Andreas Koestler + */ + trait PaddedGrouper[T, N <: Nat, Step <: Nat, Pad] extends DepFn2[T, Pad] with Serializable + + object PaddedGrouper { + def apply[T, N <: Nat, Step <: Nat, Pad](implicit + grouper: PaddedGrouper[T, N, Step, Pad] + ): Aux[T, N, Step, Pad, grouper.Out] = grouper + + type Aux[T, N <: Nat, Step <: Nat, Pad, Out0] = PaddedGrouper[T, N, Step, Pad] {type Out = Out0} + + implicit def tuplePaddedGrouper[Pad, PadL <: HList, T, N <: Nat, Step <: Nat, L <: HList, OutL <: HList] + (implicit + genL: Generic.Aux[T, L], + genPad: Generic.Aux[Pad, PadL], + grouper: hl.PaddedGrouper.Aux[L, N, Step, PadL, OutL], + tupler: hl.Tupler[OutL] + ): Aux[T, N, Step, Pad, tupler.Out] = new PaddedGrouper[T, N, Step, Pad] { + type Out = tupler.Out + + def apply(t: T, pad: Pad): Out = tupler(grouper(genL.to(t), genPad.to(pad))) + } + + } + + /** + * Type class supporting permuting this `Tuple` into the same order as another `Tuple` with + * the same element types. + * + * @author Peter Neyens + */ + @implicitNotFound("Implicit not found: shapeless.ops.tuple.Align[${T}, ${U}]. The types ${T} and ${U} cannot be aligned.") + trait Align[T, U] extends (T => U) with Serializable { + def apply(t: T): U + } + + object Align { + def apply[T, U](implicit align: Align[T, U]): Align[T, U] = align + + implicit def tupleAlign[T, U, L <: HList, M <: HList] + (implicit + gent: Generic.Aux[T, L], + genu: Generic.Aux[U, M], + align: hl.Align[L, M], + tp: hl.Tupler.Aux[M, U] + ): Align[T, U] = + new Align[T, U] { + def apply(t: T): U = align(gent.to(t)).tupled + } + } } \ No newline at end of file diff --git a/core/src/main/scala/shapeless/ops/zipper.scala b/core/src/main/scala/shapeless/ops/zipper.scala index 714c37d2a..d348ba87f 100644 --- a/core/src/main/scala/shapeless/ops/zipper.scala +++ b/core/src/main/scala/shapeless/ops/zipper.scala @@ -1,333 +1,333 @@ -/* - * Copyright (c) 2012-15 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless -package ops - -import hlist.{ IsHCons, ReversePrepend, Split, SplitLeft } - -object zipper { - trait Right[Z] extends DepFn1[Z] with Serializable - - object Right { - def apply[Z](implicit right: Right[Z]): Aux[Z, right.Out] = right - - type Aux[Z, Out0] = Right[Z] { type Out = Out0 } - - implicit def right[C, L <: HList, RH, RT <: HList, P]: Aux[Zipper[C, L, RH :: RT, P], Zipper[C, RH :: L, RT, P]] = - new Right[Zipper[C, L, RH :: RT, P]] { - type Out = Zipper[C, RH :: L, RT, P] - def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(z.suffix.head :: z.prefix, z.suffix.tail, z.parent) - } - } - - trait Left[Z] extends DepFn1[Z] with Serializable - - object Left { - def apply[Z](implicit left: Left[Z]): Aux[Z, left.Out] = left - - type Aux[Z, Out0] = Left[Z] { type Out = Out0 } - - implicit def left[C, LH, LT <: HList, R <: HList, P]: Aux[Zipper[C, LH :: LT, R, P], Zipper[C, LT, LH :: R, P]] = - new Left[Zipper[C, LH :: LT, R, P]] { - type Out = Zipper[C, LT, LH :: R, P] - def apply(z: Zipper[C, LH :: LT, R, P]) = Zipper(z.prefix.tail, z.prefix.head :: z.suffix, z.parent) - } - } - - trait First[Z] extends DepFn1[Z] with Serializable - - object First { - def apply[Z](implicit first: First[Z]): Aux[Z, first.Out] = first - - type Aux[Z, Out0] = First[Z] { type Out = Out0 } - - implicit def first[C, L <: HList, R <: HList, RP <: HList, P] - (implicit rp: ReversePrepend.Aux[L, R, RP]): Aux[Zipper[C, L, R, P], Zipper[C, HNil, RP, P]] = - new First[Zipper[C, L, R, P]] { - type Out = Zipper[C, HNil, RP, P] - def apply(z: Zipper[C, L, R, P]) = Zipper(HNil, z.prefix reverse_::: z.suffix, z.parent) - } - } - - trait Last[Z] extends DepFn1[Z] with Serializable - - object Last { - def apply[Z](implicit last: Last[Z]): Aux[Z, last.Out] = last - - type Aux[Z, Out0] = Last[Z] { type Out = Out0 } - - implicit def last[C, L <: HList, R <: HList, RP <: HList, P] - (implicit rp: ReversePrepend.Aux[R, L, RP]): Aux[Zipper[C, L, R, P], Zipper[C, RP, HNil, P]] = - new Last[Zipper[C, L, R, P]] { - type Out = Zipper[C, RP, HNil, P] - def apply(z: Zipper[C, L, R, P]) = Zipper(z.suffix reverse_::: z.prefix, HNil, z.parent) - } - } - - trait RightBy[Z, N <: Nat] extends DepFn1[Z] with Serializable - - object RightBy { - def apply[Z, N <: Nat](implicit rightBy: RightBy[Z, N]): Aux[Z, N, rightBy.Out] = rightBy - - type Aux[Z, N <: Nat, Out0] = RightBy[Z, N] { type Out = Out0 } - - implicit def rightBy[C, L <: HList, R <: HList, P, N <: Nat, LP <: HList, RS <: HList] - (implicit - split: Split.Aux[R, N, LP, RS], - reverse: ReversePrepend[LP, L]): Aux[Zipper[C, L, R, P], N, Zipper[C, reverse.Out, RS, P]] = - new RightBy[Zipper[C, L, R, P], N] { - type Out = Zipper[C, reverse.Out, RS, P] - def apply(z: Zipper[C, L, R, P]) = { - val p :: s :: HNil = z.suffix.splitP[N] - Zipper(p reverse_::: z.prefix, s, z.parent) - } - } - } - - trait LeftBy[Z, N <: Nat] extends DepFn1[Z] with Serializable - - object LeftBy { - def apply[Z, N <: Nat](implicit leftBy: LeftBy[Z, N]): Aux[Z, N, leftBy.Out] = leftBy - - type Aux[Z, N <: Nat, Out0] = LeftBy[Z, N] { type Out = Out0 } - - implicit def leftBy[C, L <: HList, R <: HList, P, N <: Nat, RP <: HList, LS <: HList] - (implicit - split: Split.Aux[L, N, RP, LS], - reverse: ReversePrepend[RP, R]): Aux[Zipper[C, L, R, P], N, Zipper[C, LS, reverse.Out, P]] = - new LeftBy[Zipper[C, L, R, P], N] { - type Out = Zipper[C, LS, reverse.Out, P] - def apply(z: Zipper[C, L, R, P]) = { - val p :: s :: HNil = z.prefix.splitP[N] - Zipper(s, p reverse_::: z.suffix, z.parent) - } - } - } - - trait RightTo[Z, T] extends DepFn1[Z] with Serializable - - object RightTo { - def apply[Z, T](implicit rightTo: RightTo[Z, T]): Aux[Z, T, rightTo.Out] = rightTo - - type Aux[Z, T, Out0] = RightTo[Z, T] { type Out = Out0 } - - implicit def rightTo[C, L <: HList, R <: HList, P, T, LP <: HList, RS <: HList] - (implicit - split: SplitLeft.Aux[R, T, LP, RS], - reverse: ReversePrepend[LP, L]): Aux[Zipper[C, L, R, P], T, Zipper[C, reverse.Out, RS, P]] = - new RightTo[Zipper[C, L, R, P], T] { - type Out = Zipper[C, reverse.Out, RS, P] - def apply(z: Zipper[C, L, R, P]) = { - val p :: s :: HNil = z.suffix.splitLeftP[T] - Zipper(p reverse_::: z.prefix, s, z.parent) - } - } - } - - trait LeftTo[Z, T] extends DepFn1[Z] with Serializable - - object LeftTo { - def apply[Z, T](implicit leftTo: LeftTo[Z, T]): Aux[Z, T, leftTo.Out] = leftTo - - type Aux[Z, T, Out0] = LeftTo[Z, T] { type Out = Out0 } - - implicit def leftTo[C, L <: HList, R <: HList, P, T, RP <: HList, R0 <: HList] - (implicit - split: SplitLeft.Aux[L, T, RP, R0], - reverse: ReversePrepend[RP, R], - cons: IsHCons[R0]): Aux[Zipper[C, L, R, P], T, Zipper[C, cons.T, cons.H :: reverse.Out, P]] = - new LeftTo[Zipper[C, L, R, P], T] { - type Out = Zipper[C, cons.T, cons.H :: reverse.Out, P] - def apply(z: Zipper[C, L, R, P]) = { - val p :: s :: HNil = z.prefix.splitLeftP[T] - Zipper(s.tail, s.head :: (p reverse_::: z.suffix), z.parent) - } - } - } - - trait Up[Z] extends DepFn1[Z] with Serializable - - object Up { - def apply[Z](implicit up: Up[Z]): Aux[Z, up.Out] = up - - type Aux[Z, Out0] = Up[Z] { type Out = Out0 } - - implicit def up[C, L <: HList, R <: HList, P] - (implicit - rz: Reify.Aux[Zipper[C, L, R, Some[P]], C], - pp: Put[P, C]): Aux[Zipper[C, L, R, Some[P]], pp.Out] = - new Up[Zipper[C, L, R, Some[P]]] { - type Out = pp.Out - def apply(z: Zipper[C, L, R, Some[P]]) = pp(z.parent.get, z.reify) - } - } - - trait Down[Z] extends DepFn1[Z] with Serializable - - object Down { - def apply[Z](implicit down: Down[Z]): Aux[Z, down.Out] = down - - type Aux[Z, Out0] = Down[Z] { type Out = Out0 } - - implicit def hlistDown[C, L <: HList, RH <: HList, RT <: HList, P]: - Aux[Zipper[C, L, RH :: RT, P], Zipper[RH, HNil, RH, Some[Zipper[C, L, RH :: RT, P]]]] = - new Down[Zipper[C, L, RH :: RT, P]] { - type Out = Zipper[RH, HNil, RH, Some[Zipper[C, L, RH :: RT, P]]] - def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(HNil, z.suffix.head, Some(z)) - } - - implicit def genericDown[C, L <: HList, RH, RT <: HList, P, RHL <: HList](implicit gen: Generic.Aux[RH, RHL]): - Aux[Zipper[C, L, RH :: RT, P], Zipper[RH, HNil, RHL, Some[Zipper[C, L, RH :: RT, P]]]] = - new Down[Zipper[C, L, RH :: RT, P]] { - type Out = Zipper[RH, HNil, RHL, Some[Zipper[C, L, RH :: RT, P]]] - def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(HNil, gen.to(z.suffix.head), Some(z)) - } - } - - trait Root[Z] extends DepFn1[Z] with Serializable - - object Root { - def apply[Z](implicit root: Root[Z]): Aux[Z, root.Out] = root - - type Aux[Z, Out0] = Root[Z] { type Out = Out0 } - - implicit def rootRoot[C, L <: HList, R <: HList]: Aux[Zipper[C, L, R, None.type], Zipper[C, L, R, None.type]] = - new Root[Zipper[C, L, R, None.type]] { - type Out = Zipper[C, L, R, None.type] - def apply(z: Zipper[C, L, R, None.type]) = z - } - - implicit def nonRootRoot[C, L <: HList, R <: HList, P, U] - (implicit - up: Up.Aux[Zipper[C, L, R, Some[P]], U], - pr: Root[U]): Aux[Zipper[C, L, R, Some[P]], pr.Out] = - new Root[Zipper[C, L, R, Some[P]]] { - type Out = pr.Out - def apply(z: Zipper[C, L, R, Some[P]]) = pr(z.up) - } - } - - trait Get[Z] extends DepFn1[Z] with Serializable - - object Get { - def apply[Z](implicit get: Get[Z]): Aux[Z, get.Out] = get - - type Aux[Z, Out0] = Get[Z] { type Out = Out0 } - - implicit def get[C, L <: HList, RH, RT <: HList, P]: Aux[Zipper[C, L, RH :: RT, P], RH] = - new Get[Zipper[C, L, RH :: RT, P]] { - type Out = RH - def apply(z: Zipper[C, L, RH :: RT, P]) = z.suffix.head - } - } - - trait Put[Z, E] extends DepFn2[Z, E] with Serializable - - object Put { - def apply[Z, E](implicit put: Put[Z, E]): Aux[Z, E, put.Out] = put - - type Aux[Z, E, Out0] = Put[Z, E] { type Out = Out0 } - - implicit def genericPut[C, L <: HList, RH, RT <: HList, P, E, CL <: HList] - (implicit - gen: Generic.Aux[C, CL], - rp: ReversePrepend.Aux[L, E :: RT, CL]): Aux[Zipper[C, L, RH :: RT, P], E, Zipper[C, L, E :: RT, P]] = - new Put[Zipper[C, L, RH :: RT, P], E] { - type Out = Zipper[C, L, E :: RT, P] - def apply(z: Zipper[C, L, RH :: RT, P], e: E) = Zipper(z.prefix, e :: z.suffix.tail, z.parent) - } - - implicit def hlistPut[C <: HList, L <: HList, RH, RT <: HList, P, E, CL <: HList] - (implicit rp: ReversePrepend.Aux[L, E :: RT, CL]): Aux[Zipper[C, L, RH :: RT, P], E, Zipper[CL, L, E :: RT, P]] = - new Put[Zipper[C, L, RH :: RT, P], E] { - type Out = Zipper[CL, L, E :: RT, P] - def apply(z: Zipper[C, L, RH :: RT, P], e: E) = Zipper(z.prefix, e :: z.suffix.tail, z.parent) - } - } - - trait Modify[Z, E1, E2] extends DepFn2[Z, E1 => E2] with Serializable - - object Modify { - def apply[Z, E1, E2](implicit modify: Modify[Z, E1, E2]): Aux[Z, E1, E2, modify.Out] = modify - - type Aux[Z, E1, E2, Out0] = Modify[Z, E1, E2] { type Out = Out0 } - - implicit def modify[C, L <: HList, RH1, RT <: HList, P, RH2] - (implicit - get: Get.Aux[Zipper[C, L, RH1 :: RT, P], RH1], - put: Put.Aux[Zipper[C, L, RH1 :: RT, P], RH2, Zipper[C, L, RH2 :: RT, P]] - ): Aux[Zipper[C, L, RH1 :: RT, P], RH1, RH2, Zipper[C, L, RH2 :: RT, P]] = - new Modify[Zipper[C, L, RH1 :: RT, P], RH1, RH2] { - type Out = Zipper[C, L, RH2 :: RT, P] - def apply(z: Zipper[C, L, RH1 :: RT, P], f: RH1 => RH2) = put(z, f(get(z))) - } - } - - trait Insert[Z, E] extends DepFn2[Z, E] with Serializable - - object Insert { - def apply[Z, E](implicit insert: Insert[Z, E]): Aux[Z, E, insert.Out] = insert - - type Aux[Z, E, Out0] = Insert[Z, E] { type Out = Out0 } - - implicit def hlistInsert[C <: HList, L <: HList, R <: HList, P, E, CL <: HList] - (implicit rp: ReversePrepend.Aux[E :: L, R, CL]): Aux[Zipper[C, L, R, P], E, Zipper[CL, E :: L, R, P]] = - new Insert[Zipper[C, L, R, P], E] { - type Out = Zipper[CL, E :: L, R, P] - def apply(z: Zipper[C, L, R, P], e: E) = Zipper(e :: z.prefix, z.suffix, z.parent) - } - } - - trait Delete[Z] extends DepFn1[Z] with Serializable - - object Delete { - def apply[Z](implicit delete: Delete[Z]): Aux[Z, delete.Out] = delete - - type Aux[Z, Out0] = Delete[Z] { type Out = Out0 } - - implicit def hlistDelete[C <: HList, L <: HList, RH, RT <: HList, P, CL <: HList] - (implicit rp: ReversePrepend.Aux[L, RT, CL]): Aux[Zipper[C, L, RH :: RT, P], Zipper[CL, L, RT, P]] = - new Delete[Zipper[C, L, RH :: RT, P]] { - type Out = Zipper[CL, L, RT, P] - def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(z.prefix, z.suffix.tail, z.parent) - } - } - - trait Reify[Z] extends DepFn1[Z] with Serializable - - object Reify { - def apply[Z](implicit reify: Reify[Z]): Aux[Z, reify.Out] = reify - - type Aux[Z, Out0] = Reify[Z] { type Out = Out0 } - - implicit def hlistReify[LR <: HList, L <: HList, R <: HList, P] - (implicit rp: ReversePrepend.Aux[L, R, LR]): Aux[Zipper[LR, L, R, P], LR] = - new Reify[Zipper[LR, L, R, P]] { - type Out = LR - def apply(z: Zipper[LR, L, R, P]) = z.prefix reverse_::: z.suffix - } - - implicit def genericReify[C, L <: HList, R <: HList, P, CL <: HList] - (implicit - gen: Generic.Aux[C, CL], - rp: ReversePrepend.Aux[L, R, CL]): Aux[Zipper[C, L, R, P], C] = - new Reify[Zipper[C, L, R, P]] { - type Out = C - def apply(z: Zipper[C, L, R, P]) = gen.from(z.prefix reverse_::: z.suffix) - } - } -} +/* + * Copyright (c) 2012-15 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless +package ops + +import hlist.{ IsHCons, ReversePrepend, Split, SplitLeft } + +object zipper { + trait Right[Z] extends DepFn1[Z] with Serializable + + object Right { + def apply[Z](implicit right: Right[Z]): Aux[Z, right.Out] = right + + type Aux[Z, Out0] = Right[Z] { type Out = Out0 } + + implicit def right[C, L <: HList, RH, RT <: HList, P]: Aux[Zipper[C, L, RH :: RT, P], Zipper[C, RH :: L, RT, P]] = + new Right[Zipper[C, L, RH :: RT, P]] { + type Out = Zipper[C, RH :: L, RT, P] + def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(z.suffix.head :: z.prefix, z.suffix.tail, z.parent) + } + } + + trait Left[Z] extends DepFn1[Z] with Serializable + + object Left { + def apply[Z](implicit left: Left[Z]): Aux[Z, left.Out] = left + + type Aux[Z, Out0] = Left[Z] { type Out = Out0 } + + implicit def left[C, LH, LT <: HList, R <: HList, P]: Aux[Zipper[C, LH :: LT, R, P], Zipper[C, LT, LH :: R, P]] = + new Left[Zipper[C, LH :: LT, R, P]] { + type Out = Zipper[C, LT, LH :: R, P] + def apply(z: Zipper[C, LH :: LT, R, P]) = Zipper(z.prefix.tail, z.prefix.head :: z.suffix, z.parent) + } + } + + trait First[Z] extends DepFn1[Z] with Serializable + + object First { + def apply[Z](implicit first: First[Z]): Aux[Z, first.Out] = first + + type Aux[Z, Out0] = First[Z] { type Out = Out0 } + + implicit def first[C, L <: HList, R <: HList, RP <: HList, P] + (implicit rp: ReversePrepend.Aux[L, R, RP]): Aux[Zipper[C, L, R, P], Zipper[C, HNil, RP, P]] = + new First[Zipper[C, L, R, P]] { + type Out = Zipper[C, HNil, RP, P] + def apply(z: Zipper[C, L, R, P]) = Zipper(HNil, z.prefix reverse_::: z.suffix, z.parent) + } + } + + trait Last[Z] extends DepFn1[Z] with Serializable + + object Last { + def apply[Z](implicit last: Last[Z]): Aux[Z, last.Out] = last + + type Aux[Z, Out0] = Last[Z] { type Out = Out0 } + + implicit def last[C, L <: HList, R <: HList, RP <: HList, P] + (implicit rp: ReversePrepend.Aux[R, L, RP]): Aux[Zipper[C, L, R, P], Zipper[C, RP, HNil, P]] = + new Last[Zipper[C, L, R, P]] { + type Out = Zipper[C, RP, HNil, P] + def apply(z: Zipper[C, L, R, P]) = Zipper(z.suffix reverse_::: z.prefix, HNil, z.parent) + } + } + + trait RightBy[Z, N <: Nat] extends DepFn1[Z] with Serializable + + object RightBy { + def apply[Z, N <: Nat](implicit rightBy: RightBy[Z, N]): Aux[Z, N, rightBy.Out] = rightBy + + type Aux[Z, N <: Nat, Out0] = RightBy[Z, N] { type Out = Out0 } + + implicit def rightBy[C, L <: HList, R <: HList, P, N <: Nat, LP <: HList, RS <: HList] + (implicit + split: Split.Aux[R, N, LP, RS], + reverse: ReversePrepend[LP, L]): Aux[Zipper[C, L, R, P], N, Zipper[C, reverse.Out, RS, P]] = + new RightBy[Zipper[C, L, R, P], N] { + type Out = Zipper[C, reverse.Out, RS, P] + def apply(z: Zipper[C, L, R, P]) = { + val p :: s :: HNil = z.suffix.splitP[N] : @unchecked + Zipper(p reverse_::: z.prefix, s, z.parent) + } + } + } + + trait LeftBy[Z, N <: Nat] extends DepFn1[Z] with Serializable + + object LeftBy { + def apply[Z, N <: Nat](implicit leftBy: LeftBy[Z, N]): Aux[Z, N, leftBy.Out] = leftBy + + type Aux[Z, N <: Nat, Out0] = LeftBy[Z, N] { type Out = Out0 } + + implicit def leftBy[C, L <: HList, R <: HList, P, N <: Nat, RP <: HList, LS <: HList] + (implicit + split: Split.Aux[L, N, RP, LS], + reverse: ReversePrepend[RP, R]): Aux[Zipper[C, L, R, P], N, Zipper[C, LS, reverse.Out, P]] = + new LeftBy[Zipper[C, L, R, P], N] { + type Out = Zipper[C, LS, reverse.Out, P] + def apply(z: Zipper[C, L, R, P]) = { + val p :: s :: HNil = z.prefix.splitP[N] : @unchecked + Zipper(s, p reverse_::: z.suffix, z.parent) + } + } + } + + trait RightTo[Z, T] extends DepFn1[Z] with Serializable + + object RightTo { + def apply[Z, T](implicit rightTo: RightTo[Z, T]): Aux[Z, T, rightTo.Out] = rightTo + + type Aux[Z, T, Out0] = RightTo[Z, T] { type Out = Out0 } + + implicit def rightTo[C, L <: HList, R <: HList, P, T, LP <: HList, RS <: HList] + (implicit + split: SplitLeft.Aux[R, T, LP, RS], + reverse: ReversePrepend[LP, L]): Aux[Zipper[C, L, R, P], T, Zipper[C, reverse.Out, RS, P]] = + new RightTo[Zipper[C, L, R, P], T] { + type Out = Zipper[C, reverse.Out, RS, P] + def apply(z: Zipper[C, L, R, P]) = { + val p :: s :: HNil = z.suffix.splitLeftP[T] : @unchecked + Zipper(p reverse_::: z.prefix, s, z.parent) + } + } + } + + trait LeftTo[Z, T] extends DepFn1[Z] with Serializable + + object LeftTo { + def apply[Z, T](implicit leftTo: LeftTo[Z, T]): Aux[Z, T, leftTo.Out] = leftTo + + type Aux[Z, T, Out0] = LeftTo[Z, T] { type Out = Out0 } + + implicit def leftTo[C, L <: HList, R <: HList, P, T, RP <: HList, R0 <: HList] + (implicit + split: SplitLeft.Aux[L, T, RP, R0], + reverse: ReversePrepend[RP, R], + cons: IsHCons[R0]): Aux[Zipper[C, L, R, P], T, Zipper[C, cons.T, cons.H :: reverse.Out, P]] = + new LeftTo[Zipper[C, L, R, P], T] { + type Out = Zipper[C, cons.T, cons.H :: reverse.Out, P] + def apply(z: Zipper[C, L, R, P]) = { + val p :: s :: HNil = z.prefix.splitLeftP[T] : @unchecked + Zipper(s.tail, s.head :: (p reverse_::: z.suffix), z.parent) + } + } + } + + trait Up[Z] extends DepFn1[Z] with Serializable + + object Up { + def apply[Z](implicit up: Up[Z]): Aux[Z, up.Out] = up + + type Aux[Z, Out0] = Up[Z] { type Out = Out0 } + + implicit def up[C, L <: HList, R <: HList, P] + (implicit + rz: Reify.Aux[Zipper[C, L, R, Some[P]], C], + pp: Put[P, C]): Aux[Zipper[C, L, R, Some[P]], pp.Out] = + new Up[Zipper[C, L, R, Some[P]]] { + type Out = pp.Out + def apply(z: Zipper[C, L, R, Some[P]]) = pp(z.parent.get, z.reify) + } + } + + trait Down[Z] extends DepFn1[Z] with Serializable + + object Down { + def apply[Z](implicit down: Down[Z]): Aux[Z, down.Out] = down + + type Aux[Z, Out0] = Down[Z] { type Out = Out0 } + + implicit def hlistDown[C, L <: HList, RH <: HList, RT <: HList, P]: + Aux[Zipper[C, L, RH :: RT, P], Zipper[RH, HNil, RH, Some[Zipper[C, L, RH :: RT, P]]]] = + new Down[Zipper[C, L, RH :: RT, P]] { + type Out = Zipper[RH, HNil, RH, Some[Zipper[C, L, RH :: RT, P]]] + def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(HNil, z.suffix.head, Some(z)) + } + + implicit def genericDown[C, L <: HList, RH, RT <: HList, P, RHL <: HList](implicit gen: Generic.Aux[RH, RHL]): + Aux[Zipper[C, L, RH :: RT, P], Zipper[RH, HNil, RHL, Some[Zipper[C, L, RH :: RT, P]]]] = + new Down[Zipper[C, L, RH :: RT, P]] { + type Out = Zipper[RH, HNil, RHL, Some[Zipper[C, L, RH :: RT, P]]] + def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(HNil, gen.to(z.suffix.head), Some(z)) + } + } + + trait Root[Z] extends DepFn1[Z] with Serializable + + object Root { + def apply[Z](implicit root: Root[Z]): Aux[Z, root.Out] = root + + type Aux[Z, Out0] = Root[Z] { type Out = Out0 } + + implicit def rootRoot[C, L <: HList, R <: HList]: Aux[Zipper[C, L, R, None.type], Zipper[C, L, R, None.type]] = + new Root[Zipper[C, L, R, None.type]] { + type Out = Zipper[C, L, R, None.type] + def apply(z: Zipper[C, L, R, None.type]) = z + } + + implicit def nonRootRoot[C, L <: HList, R <: HList, P, U] + (implicit + up: Up.Aux[Zipper[C, L, R, Some[P]], U], + pr: Root[U]): Aux[Zipper[C, L, R, Some[P]], pr.Out] = + new Root[Zipper[C, L, R, Some[P]]] { + type Out = pr.Out + def apply(z: Zipper[C, L, R, Some[P]]) = pr(z.up) + } + } + + trait Get[Z] extends DepFn1[Z] with Serializable + + object Get { + def apply[Z](implicit get: Get[Z]): Aux[Z, get.Out] = get + + type Aux[Z, Out0] = Get[Z] { type Out = Out0 } + + implicit def get[C, L <: HList, RH, RT <: HList, P]: Aux[Zipper[C, L, RH :: RT, P], RH] = + new Get[Zipper[C, L, RH :: RT, P]] { + type Out = RH + def apply(z: Zipper[C, L, RH :: RT, P]) = z.suffix.head + } + } + + trait Put[Z, E] extends DepFn2[Z, E] with Serializable + + object Put { + def apply[Z, E](implicit put: Put[Z, E]): Aux[Z, E, put.Out] = put + + type Aux[Z, E, Out0] = Put[Z, E] { type Out = Out0 } + + implicit def genericPut[C, L <: HList, RH, RT <: HList, P, E, CL <: HList] + (implicit + gen: Generic.Aux[C, CL], + rp: ReversePrepend.Aux[L, E :: RT, CL]): Aux[Zipper[C, L, RH :: RT, P], E, Zipper[C, L, E :: RT, P]] = + new Put[Zipper[C, L, RH :: RT, P], E] { + type Out = Zipper[C, L, E :: RT, P] + def apply(z: Zipper[C, L, RH :: RT, P], e: E) = Zipper(z.prefix, e :: z.suffix.tail, z.parent) + } + + implicit def hlistPut[C <: HList, L <: HList, RH, RT <: HList, P, E, CL <: HList] + (implicit rp: ReversePrepend.Aux[L, E :: RT, CL]): Aux[Zipper[C, L, RH :: RT, P], E, Zipper[CL, L, E :: RT, P]] = + new Put[Zipper[C, L, RH :: RT, P], E] { + type Out = Zipper[CL, L, E :: RT, P] + def apply(z: Zipper[C, L, RH :: RT, P], e: E) = Zipper(z.prefix, e :: z.suffix.tail, z.parent) + } + } + + trait Modify[Z, E1, E2] extends DepFn2[Z, E1 => E2] with Serializable + + object Modify { + def apply[Z, E1, E2](implicit modify: Modify[Z, E1, E2]): Aux[Z, E1, E2, modify.Out] = modify + + type Aux[Z, E1, E2, Out0] = Modify[Z, E1, E2] { type Out = Out0 } + + implicit def modify[C, L <: HList, RH1, RT <: HList, P, RH2] + (implicit + get: Get.Aux[Zipper[C, L, RH1 :: RT, P], RH1], + put: Put.Aux[Zipper[C, L, RH1 :: RT, P], RH2, Zipper[C, L, RH2 :: RT, P]] + ): Aux[Zipper[C, L, RH1 :: RT, P], RH1, RH2, Zipper[C, L, RH2 :: RT, P]] = + new Modify[Zipper[C, L, RH1 :: RT, P], RH1, RH2] { + type Out = Zipper[C, L, RH2 :: RT, P] + def apply(z: Zipper[C, L, RH1 :: RT, P], f: RH1 => RH2) = put(z, f(get(z))) + } + } + + trait Insert[Z, E] extends DepFn2[Z, E] with Serializable + + object Insert { + def apply[Z, E](implicit insert: Insert[Z, E]): Aux[Z, E, insert.Out] = insert + + type Aux[Z, E, Out0] = Insert[Z, E] { type Out = Out0 } + + implicit def hlistInsert[C <: HList, L <: HList, R <: HList, P, E, CL <: HList] + (implicit rp: ReversePrepend.Aux[E :: L, R, CL]): Aux[Zipper[C, L, R, P], E, Zipper[CL, E :: L, R, P]] = + new Insert[Zipper[C, L, R, P], E] { + type Out = Zipper[CL, E :: L, R, P] + def apply(z: Zipper[C, L, R, P], e: E) = Zipper(e :: z.prefix, z.suffix, z.parent) + } + } + + trait Delete[Z] extends DepFn1[Z] with Serializable + + object Delete { + def apply[Z](implicit delete: Delete[Z]): Aux[Z, delete.Out] = delete + + type Aux[Z, Out0] = Delete[Z] { type Out = Out0 } + + implicit def hlistDelete[C <: HList, L <: HList, RH, RT <: HList, P, CL <: HList] + (implicit rp: ReversePrepend.Aux[L, RT, CL]): Aux[Zipper[C, L, RH :: RT, P], Zipper[CL, L, RT, P]] = + new Delete[Zipper[C, L, RH :: RT, P]] { + type Out = Zipper[CL, L, RT, P] + def apply(z: Zipper[C, L, RH :: RT, P]) = Zipper(z.prefix, z.suffix.tail, z.parent) + } + } + + trait Reify[Z] extends DepFn1[Z] with Serializable + + object Reify { + def apply[Z](implicit reify: Reify[Z]): Aux[Z, reify.Out] = reify + + type Aux[Z, Out0] = Reify[Z] { type Out = Out0 } + + implicit def hlistReify[LR <: HList, L <: HList, R <: HList, P] + (implicit rp: ReversePrepend.Aux[L, R, LR]): Aux[Zipper[LR, L, R, P], LR] = + new Reify[Zipper[LR, L, R, P]] { + type Out = LR + def apply(z: Zipper[LR, L, R, P]) = z.prefix reverse_::: z.suffix + } + + implicit def genericReify[C, L <: HList, R <: HList, P, CL <: HList] + (implicit + gen: Generic.Aux[C, CL], + rp: ReversePrepend.Aux[L, R, CL]): Aux[Zipper[C, L, R, P], C] = + new Reify[Zipper[C, L, R, P]] { + type Out = C + def apply(z: Zipper[C, L, R, P]) = gen.from(z.prefix reverse_::: z.suffix) + } + } +} From 832308b4457b62acfdbeae13fa00197cd0ab6ae1 Mon Sep 17 00:00:00 2001 From: Katrix Date: Fri, 22 Jul 2022 15:18:46 +0200 Subject: [PATCH 32/32] Fix some warnings --- build.sbt | 40 +- core/src/main/scala-3/shapeless/generic.scala | 208 +- core/src/test/scala-3/shapeless/hlist.scala | 28 +- core/src/test/scala/shapeless/hlist.scala | 6560 ++++++++--------- 4 files changed, 3441 insertions(+), 3395 deletions(-) diff --git a/build.sbt b/build.sbt index 45f957e27..6f80df48a 100644 --- a/build.sbt +++ b/build.sbt @@ -2,7 +2,7 @@ import com.typesafe.sbt.SbtGit.GitKeys._ import sbtcrossproject.CrossProject val Scala213 = "2.13.6" -val Scala3 = "3.2.0-RC2" +val Scala3 = "3.2.0-RC2" commonSettings noPublishSettings @@ -168,6 +168,44 @@ lazy val core = crossProject(JSPlatform, JVMPlatform/* TODO, NativePlatform*/).c .settings(mimaSettings:_*) .jsSettings(commonJsSettings:_*) .jvmSettings(commonJvmSettings:_*) + .jvmSettings( + Test / sources := (Test / sources).value.filter(f => + Seq( + "testutil.scala", + "poly.scala", + //"serialization.scala", "serializationtestutils.scala", //Some errors + "adjoin.scala", + "annotation.scala", + //"constraints.scala", //Exponential errors? + "conversions.scala", + //"coproduct.scala", + "default.scala", + "fin.scala", + //"generic.scala", + //"hlist.scala", + //"hmap.scala", + //"labelledgeneric.scala", + //"LabelledGenericTests213.scala", + //"lenses.scala", + "monoid.scala", + "nat.scala", + //"natranges.scala", + "orelse.scala", + //"product.scala", + //"records.scala", //Tons of long errors. Maybe requires math? + "refute.scala", + //"singletons.scala", //Compiler crash + //"sized.scala", //Requires math + //"sybclass.scala", //Exponential errors? + //"tuples.scala", //Requires math + //"typeable.scala", //Seems broken for normal types? + "typeclass.scala", + //"typeoperators.scala", + "unions.scala", + //"unwrapped.scala", //Completely broken + "zipper.scala", + ).contains(f.name)) + ) /* TODO .nativeSettings( // disable scaladoc generation on native diff --git a/core/src/main/scala-3/shapeless/generic.scala b/core/src/main/scala-3/shapeless/generic.scala index 297539c9b..b702f6c14 100644 --- a/core/src/main/scala-3/shapeless/generic.scala +++ b/core/src/main/scala-3/shapeless/generic.scala @@ -1,100 +1,108 @@ -/* - * Copyright (c) 2012-18 Lars Hupel, Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import scala.deriving._ - -trait GenericScalaCompat extends GenericScalaCompatLowPriority { - - given Generic.Aux[Unit, HNil] = new Generic[Unit] { - override type Repr = HNil - - override def to(t: Unit): Repr = HNil - - override def from(r: Repr): Unit = () - } - - given[A <: AnyRef & Singleton](using v: ValueOf[A]): Generic.Aux[A, HNil] = new Generic[A] { - override type Repr = HNil - - override def to(t: A): Repr = HNil - - override def from(r: Repr): A = v.value - } -} - -trait GenericScalaCompatLowPriority { - - transparent inline given materializeProduct[T <: Product]( - using m: scala.deriving.Mirror.ProductOf[T] - ): Generic.Aux[T, HList.TupleToHList[m.MirroredElemTypes]] = - new Generic[T] { - override type Repr = HList.TupleToHList[m.MirroredElemTypes] - - override def to(t: T): Repr = HList.tupleToHList(scala.Tuple.fromProductTyped(t)) - - override def from(r: Repr): T = m.fromProduct(HList.hListToTuple(r)) - } - - transparent inline given materializeSum[T]( - using m: scala.deriving.Mirror.SumOf[T], - ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, - ): Generic.Aux[T, Coproduct.TupleToCoproduct[m.MirroredElemTypes]] = - new Generic[T] { - override type Repr = Coproduct.TupleToCoproduct[m.MirroredElemTypes] - - override def to(t: T): Repr = Coproduct.coproductFromOrdinal(t.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes]], m.ordinal(t)) - - override def from(r: Repr): T = ev(Coproduct.extractCoproduct(r)) - } -} - -trait LabelledGenericScalaCompat { - - type MakeFieldsProduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: HList = (Types, Labels) match { - case (EmptyTuple, EmptyTuple) => HNil - case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :: MakeFieldsProduct[types, labels] - } - - type MakeFieldsCoproduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: Coproduct = (Types, Labels) match { - case (EmptyTuple, EmptyTuple) => CNil - case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :+: MakeFieldsCoproduct[types, labels] - } - - transparent inline given materializeProduct[T <: Product]( - using m: scala.deriving.Mirror.ProductOf[T] - ): LabelledGeneric.Aux[T, MakeFieldsProduct[m.MirroredElemTypes, m.MirroredElemLabels]] = - LabelledGeneric.unsafeInstance(Generic.materializeProduct) - - transparent inline given materializeSum[T]( - using m: scala.deriving.Mirror.SumOf[T], - ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, - ): LabelledGeneric.Aux[T, MakeFieldsCoproduct[m.MirroredElemTypes, m.MirroredElemLabels]] = - LabelledGeneric.unsafeInstance(Generic.materializeSum) -} - -trait IsTupleScalaCompat { - given[T <: scala.Tuple]: IsTuple[T] = new IsTuple[T] -} - -trait HasProductGenericScalaCompat { - given [T](using Mirror.ProductOf[T]): HasProductGeneric[T] = new HasProductGeneric[T] -} - -trait HasCoproductGenericScalaCompat { - given [T](using Mirror.SumOf[T]): HasCoproductGeneric[T] = new HasCoproductGeneric[T] -} +/* + * Copyright (c) 2012-18 Lars Hupel, Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import scala.deriving._ + +trait GenericScalaCompat extends GenericScalaCompatLowPriority { + + given Generic.Aux[Unit, HNil] = new Generic[Unit] { + override type Repr = HNil + + override def to(t: Unit): Repr = HNil + + override def from(r: Repr): Unit = () + } + + given[A <: AnyRef & Singleton](using v: ValueOf[A]): Generic.Aux[A, HNil] = new Generic[A] { + override type Repr = HNil + + override def to(t: A): Repr = HNil + + override def from(r: Repr): A = v.value + } +} + +trait GenericScalaCompatLowPriority { + + transparent inline given materializeProduct[T <: Product]( + using m: scala.deriving.Mirror.ProductOf[T] + ): Generic.Aux[T, HList.TupleToHList[m.MirroredElemTypes]] = + new Generic[T] { + override type Repr = HList.TupleToHList[m.MirroredElemTypes] + + override def to(t: T): Repr = HList.tupleToHList(scala.Tuple.fromProductTyped(t)) + + override def from(r: Repr): T = m.fromProduct(HList.hListToTuple(r)) + } + + transparent inline given materializeSum[T]( + using m: scala.deriving.Mirror.SumOf[T], + ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, + ): Generic.Aux[T, Coproduct.TupleToCoproduct[m.MirroredElemTypes]] = + new Generic[T] { + override type Repr = Coproduct.TupleToCoproduct[m.MirroredElemTypes] + + override def to(t: T): Repr = Coproduct.coproductFromOrdinal(t.asInstanceOf[scala.Tuple.Union[m.MirroredElemTypes]], m.ordinal(t)) + + override def from(r: Repr): T = ev(Coproduct.extractCoproduct(r)) + } +} + +trait LabelledGenericScalaCompat { + + type MakeFieldsProduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: HList = (Types, Labels) match { + case (EmptyTuple, EmptyTuple) => HNil + case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :: MakeFieldsProduct[types, labels] + } + + type MakeFieldsCoproduct[Types <: scala.Tuple, Labels <: scala.Tuple] <: Coproduct = (Types, Labels) match { + case (EmptyTuple, EmptyTuple) => CNil + case (tpe *: types, label *: labels) => labelled.FieldType[label, tpe] :+: MakeFieldsCoproduct[types, labels] + } + + given LabelledGeneric.Aux[Unit, HNil] = new LabelledGeneric[Unit] { + override type Repr = HNil + + override def to(t: Unit): Repr = HNil + + override def from(r: Repr): Unit = () + } + + transparent inline given materializeProduct[T <: Product]( + using m: scala.deriving.Mirror.ProductOf[T] + ): LabelledGeneric.Aux[T, MakeFieldsProduct[m.MirroredElemTypes, m.MirroredElemLabels]] = + LabelledGeneric.unsafeInstance(Generic.materializeProduct) + + transparent inline given materializeSum[T]( + using m: scala.deriving.Mirror.SumOf[T], + ev: scala.Tuple.Union[Coproduct.CoproductToTuple[Coproduct.TupleToCoproduct[m.MirroredElemTypes]]] <:< T, + ): LabelledGeneric.Aux[T, MakeFieldsCoproduct[m.MirroredElemTypes, m.MirroredElemLabels]] = + LabelledGeneric.unsafeInstance(Generic.materializeSum) +} + +trait IsTupleScalaCompat { + given[T <: scala.Tuple]: IsTuple[T] = new IsTuple[T] +} + +trait HasProductGenericScalaCompat { + given [T](using Mirror.ProductOf[T]): HasProductGeneric[T] = new HasProductGeneric[T] +} + +trait HasCoproductGenericScalaCompat { + given [T](using Mirror.SumOf[T]): HasCoproductGeneric[T] = new HasCoproductGeneric[T] +} diff --git a/core/src/test/scala-3/shapeless/hlist.scala b/core/src/test/scala-3/shapeless/hlist.scala index 680664aae..363a80758 100644 --- a/core/src/test/scala-3/shapeless/hlist.scala +++ b/core/src/test/scala-3/shapeless/hlist.scala @@ -1,14 +1,14 @@ -package shapeless - -import scala.reflect.ClassTag - -trait HListTestsScalaCompat { this: HListTests => - - type PWS = Fruit - - given ClassTag[Nothing] = ClassTag.Nothing - - type MIntStringDoubleBound[A] = M[_ >: String & (Int & Double) <: String | (Int | Double), A] - type M2IntStringDoubleBound[A] = M2[_ >: String & (Int & Double) <: String | (Int | Double), A] - type AnyOrMatchable = Matchable -} +package shapeless + +import scala.reflect.ClassTag + +trait HListTestsScalaCompat { this: HListTests => + + type PWS = Fruit + + given ClassTag[Nothing] = ClassTag.Nothing + + type MIntStringDoubleBound = M[_ >: String & (Int & Double) <: String | (Int | Double)] + type M2IntStringDoubleBound[A] = M2[_ >: String & (Int & Double) <: String | (Int | Double), A] + type AnyOrMatchable = Matchable +} diff --git a/core/src/test/scala/shapeless/hlist.scala b/core/src/test/scala/shapeless/hlist.scala index 3c183e00e..55ad370fe 100644 --- a/core/src/test/scala/shapeless/hlist.scala +++ b/core/src/test/scala/shapeless/hlist.scala @@ -1,3280 +1,3280 @@ -/* - * Copyright (c) 2011-14 Miles Sabin - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package shapeless - -import org.junit.Test -import org.junit.Assert._ - -import test._ -import testutil._ - -class HListTests extends HListTestsScalaCompat { - import nat._ - import poly._ - import syntax.std.traversable._ - import syntax.singleton._ - import syntax.typeable._ - import ops.hlist._ - import ops.record.SelectAll - - type SI = Set[Int] :: HNil - type OI = Option[Int] :: HNil - - type III = Int :: Int :: Int :: HNil - - type SISS = Set[Int] :: Set[String] :: HNil - type OIOS = Option[Int] :: Option[String] :: HNil - - type ISII = Int :: String :: Int :: Int :: HNil - type IIII = Int :: Int :: Int :: Int :: HNil - type IYII = Int :: Any :: Int :: Int :: HNil - - type OIOSOIOI = Option[Int] :: Option[String] :: Option[Int] :: Option[Int] :: HNil - type SISSSISI = Set[Int] :: Set[String] :: Set[Int] :: Set[Int] :: HNil - - type BBBB = Boolean :: Boolean :: Boolean :: Boolean :: HNil - - object mkString extends (Any -> String)(_.toString) - object fruit extends (Fruit -> Fruit)(f => f) - object incInt extends (Int >-> Int)(_ + 1) - object extendedChoose extends LiftU(choose) - - trait Fruit - case class Apple() extends Fruit - case class Pear() extends Fruit - case class Banana() extends Fruit - - type YYYY = Any :: Any :: Any :: Any :: HNil - type FF = Fruit :: Fruit :: HNil - type AP = Apple :: Pear :: HNil - type BP = Banana :: Pear :: HNil - type AF = Apple :: Fruit :: HNil - type FFFF = Fruit :: Fruit :: Fruit :: Fruit :: HNil - type APAP = Apple :: Pear :: Apple :: Pear :: HNil - type APBP = Apple :: Pear :: Banana :: Pear :: HNil - type APB = Apple :: Pear :: Banana :: HNil - type PBPA = Pear :: Banana :: Pear :: Apple :: HNil - type PABP = Pear :: Apple :: Banana :: Pear :: HNil - - type APc = Apple :+: Pear :+: CNil - type ABPc = Apple :+: Banana :+: Pear :+: CNil - - val a : Apple = Apple() - val p : Pear = Pear() - val b : Banana = Banana() - val f : Fruit = new Fruit {} - - val ap : AP = a :: p :: HNil - val bp : BP = b :: p :: HNil - val apap : APAP = a :: p :: a :: p :: HNil - val apbp : APBP = a :: p :: b :: p :: HNil - val apapList = a :: p :: a :: p :: Nil - val apbpList = a :: p :: b :: p :: Nil - val apapArray = Array(a, p, a, p) - val apbpArray = Array(a, p, b, p) - - trait Ctv[-T] - type CICSCICICD = Ctv[Int] :: Ctv[String] :: Ctv[Int] :: Ctv[Int] :: Ctv[Double] :: HNil - - val ci: Ctv[Int] = new Ctv[Int] {} - val cs: Ctv[String] = new Ctv[String] {} - val cd: Ctv[Double] = new Ctv[Double] {} - val cicscicicdList = ci :: cs :: ci :: ci :: cd :: Nil - val cicscicicdArray = Array(ci, cs, ci, ci, cd) - val cicscicicd: CICSCICICD = ci :: cs :: ci :: ci :: cd :: HNil - - trait M[T] - type MIMSMIMIMD = M[Int] :: M[String] :: M[Int] :: M[Int] :: M[Double] :: HNil - - val mi: M[Int] = new M[Int] {} - val ms: M[String] = new M[String] {} - val md: M[Double] = new M[Double] {} - val mimsmimimdList = mi :: ms :: mi :: mi :: md :: Nil - val mimsmimimdArray = Array(mi, ms, mi, mi, md) - val mimsmimimd: MIMSMIMIMD = mi :: ms :: mi :: mi :: md :: HNil - - import language.existentials - val mExist: M[_] = new M[Double] {} - type MIMSMIMEMD = M[Int] :: M[String] :: M[Int] :: M[_] :: M[Double] :: HNil - val mimsmimemdList = mi :: ms :: mi :: mExist :: md :: Nil - val mimsmimemdArray = Array[M[_]](mi, ms, mi, mExist, md) - val mimsmimemd: MIMSMIMEMD = mi :: ms :: mi :: mExist :: md :: HNil - - trait M2[A,B] - type M2IM2SM2IM2IM2D = M2[Int, Unit] :: M2[String, Unit] :: M2[Int, Unit] :: M2[Int, Unit] :: M2[Double, Unit] :: HNil - - val m2i: M2[Int, Unit] = new M2[Int, Unit] {} - val m2s: M2[String, Unit] = new M2[String, Unit] {} - val m2d: M2[Double, Unit] = new M2[Double, Unit] {} - val m2im2sm2im2im2dList = m2i :: m2s :: m2i :: m2i :: m2d :: Nil - val m2im2sm2im2im2dArray = Array(m2i, m2s, m2i, m2i, m2d) - val m2im2sm2im2im2d: M2IM2SM2IM2IM2D = m2i :: m2s :: m2i :: m2i :: m2d :: HNil - - val m2iExist: M2[Int, _] = new M2[Int, Unit] {} - val m2sExist: M2[String, _] = new M2[String, Unit] {} - val m2dExist: M2[Double, _] = new M2[Double, Unit] {} - type M2EIM2ESM2EIM2EEM2ED = M2[Int, _] :: M2[String, _] :: M2[Int, _] :: M2[Int, _] :: M2[Double, _] :: HNil - val m2eim2esm2eim2eem2edList = m2iExist :: m2sExist :: m2iExist :: m2iExist :: m2dExist :: Nil - val m2eim2esm2eim2eem2edArray = Array(m2iExist, m2sExist, m2iExist, m2iExist, m2dExist) - val m2eim2esm2eim2eem2ed: M2EIM2ESM2EIM2EEM2ED = m2iExist :: m2sExist :: m2iExist :: m2iExist :: m2dExist :: HNil - - - @Test - def testBasics: Unit = { - val l = 1 :: "foo" :: 2.0 :: HNil - - val r1 = l.head - assertTypedEquals[Int](1, r1) - - val r2 = l.tail.head - assertTypedEquals[String]("foo", r2) - - assertEquals(2.0, l.tail.tail.head, Double.MinPositiveValue) - - illTyped(""" - HNil.head - """) - - illTyped(""" - HNil.tail - """) - - illTyped(""" - l.tail.tail.tail.head - """) - } - - @Test - def testMap: Unit = { - implicitly[Mapper.Aux[choose.type, HNil, HNil]] - implicitly[choose.Case[Set[Int]]] - implicitly[Mapper.Aux[choose.type, Set[Int] :: HNil, Option[Int] :: HNil]] - - val s1 = Set(1) :: HNil - val o1 = s1 map choose - assertTypedEquals[OI](Option(1) :: HNil, o1) - - val s2 = Set(1) :: Set("foo") :: HNil - val o2 = s2 map choose - assertTypedEquals[OIOS](Option(1) :: Option("foo") :: HNil, o2) - - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - - val l2 = l1 map singleton - assertTypedEquals[SISSSISI](Set(1) :: Set("foo") :: Set(2) :: Set(3) :: HNil, l2) - - val l3 = l1 map option - assertTypedEquals[OIOSOIOI](Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil, l3) - - val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - - val l5 = l4 map get - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, l5) - - typed[Int](l5.head) - typed[String](l5.tail.head) - typed[Int](l5.tail.tail.head) - typed[Int](l5.tail.tail.tail.head) - - val l6 = l1 map identity - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, l6) - - val l7 = l4 map isDefined - assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) - - val l8 = 23 :: "foo" :: true :: HNil - val l9 = l8 map mkString - assertTypedEquals[String :: String :: String :: HNil]("23" :: "foo" :: "true" :: HNil, l9) - - val l10 = apbp map fruit - assertTypedEquals[Fruit :: Fruit :: Fruit :: Fruit :: HNil](apbp, l10) - - val l11 = apbp map mkString - assertTypedEquals[String :: String :: String :: String :: HNil]("Apple()" :: "Pear()" :: "Banana()" :: "Pear()" :: HNil, l11) - } - - @Test - def testMapped: Unit = { - implicitly[Mapped.Aux[HNil, Option, HNil]] - implicitly[Mapped.Aux[Int :: String :: HNil, Option, Option[Int] :: Option[String] :: HNil]] - - implicitly[Mapped.Aux[HNil, Id, HNil]] - implicitly[Mapped.Aux[Int :: String :: HNil, Id, Int :: String :: HNil]] - - implicitly[Mapped.Aux[HNil, Const[Int]#λ, HNil]] - implicitly[Mapped.Aux[Double :: String :: HNil, Const[Int]#λ, Int :: Int :: HNil]] - } - - object dup extends Poly1 { - implicit def default[T]: Case.Aux[T, T :: T :: HNil] = at[T](t => t :: t :: HNil) - } - - @Test - def testFlatMap: Unit = { - val l1 = 1 :: "foo" :: true :: HNil - - val l2 = l1 flatMap dup - assertTypedEquals[Int :: Int :: String :: String :: Boolean :: Boolean :: HNil]( - 1 :: 1 :: "foo" :: "foo" :: true :: true :: HNil, l2) - - val l3 = (1 :: "foo" :: HNil) :: (HNil : HNil) :: (2.0 :: true :: HNil) :: ("bar" :: HNil) :: HNil - - val l4 = l3 flatMap identity - assertTypedEquals[Int :: String :: Double :: Boolean :: String :: HNil]( - 1 :: "foo" :: 2.0 :: true :: "bar" :: HNil, l4) - - val l5 = 23 :: "foo" :: 7 :: true :: 0 :: HNil - val l6 = l5 flatMap incInt - assertTypedEquals[Int :: Int :: Int :: HNil](24 :: 8 :: 1 :: HNil, l6) - - val l7 = Set(23) :: "foo" :: Set(true) :: 23 :: HNil - val l8 = l7 flatMap extendedChoose - assertTypedEquals[Option[Int] :: Option[Boolean] :: HNil](Option(23) :: Option(true) :: HNil, l8) - } - - @Test - def testConformance: Unit = { - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - assertTypedEquals[Any :: AnyRef :: Any :: Any :: HNil](1 :: "foo" :: 2 :: 3 :: HNil, l1) - - val ap = a :: p :: HNil - typed[AP](ap) - val bp = b :: p :: HNil - typed[BP](bp) - val apap = a :: p :: a :: p :: HNil - typed[APAP](apap) - val apbp = a :: p :: b :: p :: HNil - typed[APBP](apbp) - val ffff : FFFF = apap - typed[FFFF](ffff) - } - - @Test - def testLength: Unit = { - val l0 = HNil - typed[Nat._0](l0.length) - assertEquals(0, Nat toInt l0.length) - - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - typed[Nat._4](l1.length) - assertEquals(4, Nat toInt l1.length) - - val ap = a :: p :: HNil - typed[Nat._2](ap.length) - assertEquals(2, Nat toInt ap.length) - - val bp = b :: p :: HNil - typed[Nat._2](bp.length) - assertEquals(2, Nat toInt bp.length) - - val apap = a :: p :: a :: p :: HNil - typed[Nat._4](apap.length) - assertEquals(4, Nat toInt apap.length) - - val apbp = a :: p :: b :: p :: HNil - typed[Nat._4](apbp.length) - assertEquals(4, Nat toInt apbp.length) - - val ffff : FFFF = apap - typed[Nat._4](ffff.length) - assertEquals(4, Nat toInt ffff.length) - } - - @Test - def testRuntimeLength: Unit = { - assertEquals(0, HNil.runtimeLength) - assertEquals(1, (123 :: HNil).runtimeLength) - assertEquals(2, ("abc" :: 123 :: HNil).runtimeLength) - } - - @Test - def testRuntimeList: Unit = { - assertEquals(Nil, HNil.runtimeList) - assertEquals(123 :: Nil, (123 :: HNil).runtimeList) - assertEquals("abc" :: 123 :: Nil, ("abc" :: 123 :: HNil).runtimeList) - } - - @Test - def testInitLast: Unit = { - - val lp = apbp.last - assertTypedEquals[Pear](p, lp) - - val iapb = apbp.init - assertTypedEquals[APB](a :: p :: b :: HNil, iapb) - } - - @Test - def testAlign: Unit = { - type M0 = Int :: String :: Boolean :: HNil - type M1 = Int :: Boolean :: String :: HNil - type M2 = String :: Int :: Boolean :: HNil - type M3 = String :: Boolean :: Int :: HNil - type M4 = Boolean :: Int :: String :: HNil - type M5 = Boolean :: String :: Int :: HNil - - val m0 = 13 :: "bar" :: false :: HNil - val m1 = 13 :: false :: "bar" :: HNil - val m2 = "bar" :: 13 :: false :: HNil - val m3 = "bar" :: false :: 13 :: HNil - val m4 = false :: 13 :: "bar" :: HNil - val m5 = false :: "bar" :: 13 :: HNil - - val l = 23 :: "foo" :: true :: HNil - - val a0 = l.align(m0) - assertTypedEquals[M0](23 :: "foo" :: true :: HNil, a0) - - val a1 = l.align(m1) - assertTypedEquals[M1](23 :: true :: "foo" :: HNil, a1) - - val a2 = l.align(m2) - assertTypedEquals[M2]("foo" :: 23 :: true :: HNil, a2) - - val a3 = l.align(m3) - assertTypedEquals[M3]("foo" :: true :: 23 :: HNil, a3) - - val a4 = l.align(m4) - assertTypedEquals[M4](true :: 23 :: "foo" :: HNil, a4) - - val a5 = l.align(m5) - assertTypedEquals[M5](true :: "foo" :: 23 :: HNil, a5) - - val b0 = l.align[M0] - assertTypedEquals[M0](23 :: "foo" :: true :: HNil, b0) - - val b1 = l.align[M1] - assertTypedEquals[M1](23 :: true :: "foo" :: HNil, b1) - - val b2 = l.align[M2] - assertTypedEquals[M2]("foo" :: 23 :: true :: HNil, b2) - - val b3 = l.align[M3] - assertTypedEquals[M3]("foo" :: true :: 23 :: HNil, b3) - - val b4 = l.align[M4] - assertTypedEquals[M4](true :: 23 :: "foo" :: HNil, b4) - - val b5 = l.align[M5] - assertTypedEquals[M5](true :: "foo" :: 23 :: HNil, b5) - - val c0 = (HNil: HNil).align[HNil] - typed[HNil](c0) - - val c1 = (23 :: HNil).align[Int :: HNil] - typed[Int :: HNil](c1) - - val c2 = (23 :: "foo" :: HNil).align[String :: Int :: HNil] - typed[String :: Int :: HNil](c2) - - illTyped(""" - (HNil: HNil).align[Int :: HNil] - """) - - illTyped(""" - (23 :: HNil).align[String :: HNil] - """) - - illTyped(""" - (23 :: "foo" :: HNil).align[String :: String :: HNil] - """) - } - - @Test - def testReverse: Unit = { - val pbpa = apbp.reverse - assertTypedEquals[PBPA](p :: b :: p :: a :: HNil, pbpa) - - val al = a :: HNil - val ral = al.reverse - assertTypedEquals[Apple :: HNil](a :: HNil, ral) - } - - @Test - def testPrepend: Unit = { - val apbp2 = ap ::: bp - assertTypedEquals[APBP](a :: p :: b :: p :: HNil, apbp2) - val apbp2inv = implicitly[Prepend.Aux[AP, BP, APBP]].inverse(apbp2) - assertTypedEquals[AP](ap, apbp2inv._1) - assertTypedEquals[BP](bp, apbp2inv._2) - - typed[Apple](apbp2.head) - typed[Pear](apbp2.tail.head) - typed[Banana](apbp2.tail.tail.head) - typed[Pear](apbp2.tail.tail.tail.head) - - val pabp = ap reverse_::: bp - assertTypedEquals[PABP](p :: a :: b :: p :: HNil, pabp) - - { - // must compile without requiring an implicit Prepend - def prependWithHNil[L <: HList](list: L) = HNil ::: list - def prependToHNil[L <: HList](list: L) = list ::: HNil - - val r1 = prependWithHNil(ap) - assertTypedSame[AP](ap, r1) - val r1inv = implicitly[Prepend.Aux[HNil, AP, AP]].inverse(r1) - assertTypedSame[HNil](HNil, r1inv._1) - assertTypedSame[AP](ap, r1inv._2) - - val r2 = prependToHNil(ap) - assertTypedSame[AP](ap, r2) - val r2inv = implicitly[Prepend.Aux[AP, HNil, AP]].inverse(r2) - assertTypedSame[AP](ap, r2inv._1) - assertTypedSame[HNil](HNil, r2inv._2) - - val r3 = HNil ::: HNil - assertTypedSame[HNil](HNil, r3) - val r3inv = implicitly[Prepend.Aux[HNil, HNil, HNil]].inverse(r3) - assertTypedSame[HNil](HNil, r3inv._1) - assertTypedSame[HNil](HNil, r3inv._2) - - val r4 = prependWithHNil(pabp) - assertTypedSame[PABP](pabp, r4) - val r4inv = implicitly[Prepend.Aux[HNil, PABP, PABP]].inverse(r4) - assertTypedSame[HNil](HNil, r4inv._1) - assertTypedSame[PABP](pabp, r4inv._2) - - val r5 = prependToHNil(pabp) - assertTypedSame[PABP](pabp, r5) - val r5inv = implicitly[Prepend.Aux[PABP, HNil, PABP]].inverse(r5) - assertTypedSame[PABP](pabp, r5inv._1) - assertTypedSame[HNil](HNil, r5inv._2) - } - - { - // must also pass with the default implicit - val r1 = HNil ::: ap - assertTypedSame[AP](ap, r1) - val r1inv = implicitly[Prepend.Aux[HNil, AP, AP]].inverse(r1) - assertTypedSame[HNil](HNil, r1inv._1) - assertTypedSame[AP](ap, r1inv._2) - - val r2 = ap ::: HNil - assertTypedSame[AP](ap, r2) - val r2inv = implicitly[Prepend.Aux[AP, HNil, AP]].inverse(r2) - assertTypedSame[AP](ap, r2inv._1) - assertTypedSame[HNil](HNil, r2inv._2) - - val r4 = HNil ::: pabp - assertTypedSame[PABP](pabp, r4) - val r4inv = implicitly[Prepend.Aux[HNil, PABP, PABP]].inverse(r4) - assertTypedSame[HNil](HNil, r4inv._1) - assertTypedSame[PABP](pabp, r4inv._2) - - val r5 = pabp ::: HNil - assertTypedSame[PABP](pabp, r5) - val r5inv = implicitly[Prepend.Aux[PABP, HNil, PABP]].inverse(r5) - assertTypedSame[PABP](pabp, r5inv._1) - assertTypedSame[HNil](HNil, r5inv._2) - } - - { - // must compile without requiring an implicit ReversePrepend - def reversePrependWithHNil[L <: HList](list: L) = HNil reverse_::: list - def reversePrependToHNil[L <: HList : Reverse](list: L) = list reverse_::: HNil - val r4 = reversePrependWithHNil(ap) - assertTypedSame[AP](ap, r4) - val r5 = reversePrependToHNil(ap) - assertTypedEquals[Pear :: Apple :: HNil](ap.reverse, r5) - val r6 = HNil reverse_::: HNil - assertTypedSame[HNil](HNil, r6) - } - } - - @Test - def testRepeat: Unit = { - val ap2 = ap.repeat[Nat._2] - assertTypedEquals[Apple :: Pear :: Apple :: Pear :: HNil](ap2, a :: p :: a :: p :: HNil) - - val ap4 = ap.repeat[Nat._4] - assertTypedEquals[Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: HNil]( - ap4, a :: p :: a :: p :: a :: p :: a :: p :: HNil - ) - - val ap2_2 = ap2.repeat[Nat._2] - assertTypedEquals[Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: HNil](ap2_2, ap4) - - { - // repeating 1 times is identity - val ap1 = ap.repeat[Nat._1] - assertTypedEquals[AP](ap, ap1) - } - - { - // can not repeat zero times - illTyped("""ap.repeat[Nat._0]""") - } - - } - - @Test - def testToSizedList: Unit = { - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val hnil = HNil - val snil = hnil.toSized[List] - assertEquals(Nat toInt hnil.length, snil.length) - val expectedUnsized = List.empty[Nothing] - equalInferredTypes(expectedUnsized, snil.unsized) - assertEquals(expectedUnsized, snil.unsized) - - implicitly[ToSized.Aux[HNil, List, Nothing, _0]] - implicitly[ToSized.Aux[HNil, List, Int, _0]] - - { - implicitly[ToSized.Aux[M[Int] :: HNil, List, M[Int], _1]] - implicitly[ToSized.Aux[M[Int] :: HNil, List, M[_], _1]] - } - - val sizedApap = apap.toSized[List] - assertEquals(Nat toInt apap.length, sizedApap.length) - equalInferredTypes(apapList, sizedApap.unsized) - assertEquals(apapList, sizedApap.unsized) - - val sizedApbp = apbp.toSized[List] - assertEquals(Nat toInt apbp.length, sizedApbp.length) - equalInferredTypes(apbpList, sizedApbp.unsized) - assertEquals(apbpList, sizedApbp.unsized) - - val sizedCicscicicd = cicscicicd.toSized[List] - assertEquals(Nat toInt cicscicicd.length, sizedCicscicicd.length) - equalInferredTypes(cicscicicdList, sizedCicscicicd.unsized) - assertEquals(cicscicicdList, sizedCicscicicd.unsized) - - val sizedMimsmimimd = mimsmimimd.toSized[List] - assertEquals(Nat toInt mimsmimimd.length, sizedMimsmimimd.length) - equalInferredTypes(mimsmimimdList, sizedMimsmimimd.unsized) - assertEquals(mimsmimimdList, sizedMimsmimimd.unsized) - - val sizedMimsmimemd = mimsmimemd.toSized[List] - assertEquals(Nat toInt mimsmimemd.length, sizedMimsmimemd.length) - // equalInferredTypes(mimsmimemdList, sizedMimsmimemd.unsized) - typed[List[M[_]]](sizedMimsmimemd.unsized) - assertEquals(mimsmimemdList, sizedMimsmimemd.unsized) - - val sizedM2im2sm2im2im2d = m2im2sm2im2im2d.toSized[List] - assertEquals(Nat toInt m2im2sm2im2im2d.length, sizedM2im2sm2im2im2d.length) - equalInferredTypes(m2im2sm2im2im2dList, sizedM2im2sm2im2im2d.unsized) - assertEquals(m2im2sm2im2im2dList, sizedM2im2sm2im2im2d.unsized) - - val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[List] - assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) - // equalInferredTypes(m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) - assertTypedEquals[List[M2IntStringDoubleBound[_]]]( - m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) - } - - @Test - def testToSizedArray: Unit = { - def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = - assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) - - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val hnil = HNil - val snil = hnil.toSized[Array] - assertEquals(Nat toInt hnil.length, snil.length) - val expectedUnsized = Array.empty[Nothing] - equalInferredTypes(expectedUnsized, snil.unsized) - assertArrayEquals2(expectedUnsized, snil.unsized) - - implicitly[ToSized.Aux[HNil, Array, Nothing, _0]] - implicitly[ToSized.Aux[HNil, Array, Int, _0]] - - val sizedApap = apap.toSized[Array] - assertEquals(Nat toInt apap.length, sizedApap.length) - equalInferredTypes(apapArray, sizedApap.unsized) - assertArrayEquals2(apapArray, sizedApap.unsized) - - val sizedApbp = apbp.toSized[Array] - assertEquals(Nat toInt apbp.length, sizedApbp.length) - equalInferredTypes(apbpArray, sizedApbp.unsized) - assertArrayEquals2(apbpArray, sizedApbp.unsized) - - val sizedCicscicicd = cicscicicd.toSized[Array] - assertEquals(Nat toInt cicscicicd.length, sizedCicscicicd.length) - equalInferredTypes(cicscicicdArray, sizedCicscicicd.unsized) - assertArrayEquals2(cicscicicdArray, sizedCicscicicd.unsized) - - val sizedMimsmimimd = mimsmimimd.toSized[Array] - assertEquals(Nat toInt mimsmimimd.length, sizedMimsmimimd.length) - equalInferredTypes(mimsmimimdArray, sizedMimsmimimd.unsized) - assertArrayEquals2(mimsmimimdArray, sizedMimsmimimd.unsized) - - val sizedMimsmimemd = mimsmimemd.toSized[Array] - assertEquals(Nat toInt mimsmimemd.length, sizedMimsmimemd.length) - // equalInferredTypes(mimsmimemdArray, sizedMimsmimemd.unsized) - typed[Array[M[_]]](sizedMimsmimemd.unsized) - assertArrayEquals2(mimsmimemdArray, sizedMimsmimemd.unsized) - - val sizedM2im2sm2im2im2d = m2im2sm2im2im2d.toSized[Array] - assertEquals(Nat toInt m2im2sm2im2im2d.length, sizedM2im2sm2im2im2d.length) - equalInferredTypes(m2im2sm2im2im2dArray, sizedM2im2sm2im2im2d.unsized) - assertArrayEquals2(m2im2sm2im2im2dArray, sizedM2im2sm2im2im2d.unsized) - - val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[Array] - assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) - // equalInferredTypes(m2eim2esm2eim2eem2edArray, sizedM2eim2esm2eim2eem2ed.unsized) - typed[Array[M2IntStringDoubleBound[_]]](sizedM2eim2esm2eim2eem2ed.unsized) - assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x: Any), sizedM2eim2esm2eim2eem2ed.unsized.map(x => x: Any)) - } - - @Test - def testUnifier: Unit = { - def lub[X, Y, L](x : X, y : Y)(implicit lb : Lub[X, Y, L]) : (L, L) = (lb.left(x), lb.right(y)) - - val u21 = lub(a, a) - typed[(Apple, Apple)](u21) - val u22 = lub(a, p) - typed[(Fruit, Fruit)](u22) - val u23 = lub(a, f) - typed[(Fruit, Fruit)](u23) - val u24 = lub(p, a) - typed[(Fruit, Fruit)](u24) - val u25 = lub(p, p) - typed[(Pear, Pear)](u25) - val u26 = lub(f, f) - typed[(Fruit, Fruit)](u26) - val u27 = lub(f, a) - typed[(Fruit, Fruit)](u27) - val u28 = lub(f, p) - typed[(Fruit, Fruit)](u28) - val u29 = lub(f, f) - typed[(Fruit, Fruit)](u29) - - implicitly[Lub[HNil, HNil, HNil]] - implicitly[Lub[Apple :: HNil, Apple :: HNil, Apple :: HNil]] - implicitly[Lub[Fruit :: Pear :: HNil, Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil]] - implicitly[Lub[Apple :: Pear :: HNil, Pear :: Apple :: HNil, Fruit :: Fruit :: HNil]] - implicitly[Lub[ISII, IIII, IYII]] - - val u31 = lub(HNil, HNil) - typed[(HNil, HNil)](u31) - val u32 = lub(a :: HNil, a :: HNil) - typed[(Apple :: HNil, Apple :: HNil)](u32) - val u33 = lub(f :: p :: HNil, f :: f :: HNil) - typed[(Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil)](u33) - val u34 = lub(a :: p :: HNil, p :: a :: HNil) - typed[(Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil)](u34) - val u35 = lub(1 :: "two" :: 3 :: 4 :: HNil, 1 :: 2 :: 3 :: 4 :: HNil) - typed[(Int :: Any :: Int :: Int :: HNil, Int :: Any :: Int :: Int :: HNil)](u35) - - implicitly[Unifier.Aux[Apple :: HNil, Apple :: HNil]] - implicitly[Unifier.Aux[Fruit :: Pear :: HNil, Fruit :: Fruit :: HNil]] - implicitly[Unifier.Aux[Apple :: Pear :: HNil, Fruit :: Fruit :: HNil]] - - implicitly[Unifier.Aux[Int :: String :: Int :: Int :: HNil, YYYY]] - - val uapap = implicitly[Unifier.Aux[Apple :: Pear :: Apple :: Pear :: HNil, FFFF]] - val unified1 = uapap(apap) - typed[FFFF](unified1) - val unified2 = apap.unify - typed[FFFF](unified2) - - val ununified1 = unified2.cast[APAP] - assertTrue(ununified1.isDefined) - typed[APAP](ununified1.get) - val ununified2 = unified2.cast[APBP] - assertFalse(ununified2.isDefined) - typed[Option[APBP]](ununified2) - - def getUnifier[L <: HList, Out <: HList](l : L)(implicit u : Unifier.Aux[L, Out]) = u - - val u2 = getUnifier(a :: HNil) - typed[Unifier.Aux[Apple :: HNil, Apple :: HNil]](u2) - val u3 = getUnifier(a :: a :: HNil) - typed[Unifier.Aux[Apple :: Apple :: HNil, Apple :: Apple :: HNil]](u3) - val u4 = getUnifier(a :: a :: a :: HNil) - typed[Unifier.Aux[Apple :: Apple :: Apple :: HNil, Apple :: Apple :: Apple :: HNil]](u4) - val u5 = getUnifier(a :: a :: a :: a :: HNil) - typed[Unifier.Aux[Apple :: Apple :: Apple :: Apple :: HNil, Apple :: Apple :: Apple :: Apple :: HNil]](u5) - val u6 = getUnifier(a :: p :: HNil) - //typed[Unifier.Aux[Apple :: Pear :: HNil, Fruit :: Fruit :: HNil]](u6) - val u7 = getUnifier(a :: f :: HNil) - typed[Unifier.Aux[Apple :: Fruit :: HNil, Fruit :: Fruit :: HNil]](u7) - val u8 = getUnifier(f :: a :: HNil) - typed[Unifier.Aux[Fruit :: Apple :: HNil, Fruit :: Fruit :: HNil]](u8) - val u9a = getUnifier(a :: f :: HNil) - typed[Unifier.Aux[Apple :: Fruit :: HNil, FF]](u9a) - val u9b = getUnifier(a :: p :: HNil) - typed[Unifier.Aux[Apple :: Pear :: HNil, PWS :: PWS :: HNil]](u9b) - val u10 = getUnifier(apap) - typed[Unifier.Aux[APAP, PWS :: PWS :: PWS :: PWS :: HNil]](u10) - val u11 = getUnifier(apbp) - typed[Unifier.Aux[APBP, PWS :: PWS :: PWS :: PWS :: HNil]](u11) - - val invar1 = Set(23) :: Set("foo") :: HNil - val uinvar1 = invar1.unify - typed[Set[_ >: Int with String] :: Set[_ >: Int with String] :: HNil](uinvar1) - - // Unifying three or more elements which have an invariant outer type constructor and differing type - // arguments fails, presumably due to a failure to compute a sensible LUB. - //val invar2 = Set(23) :: Set("foo") :: Set(true) :: HNil - //val uinvar2 = invar.unify - } - - @Test - def testSubtypeUnifier: Unit = { - val fruits : Apple :: Pear :: Fruit :: HNil = a :: p :: f :: HNil - typed[Fruit :: Fruit :: Fruit :: HNil](fruits.unifySubtypes[Fruit]) - typed[Apple :: Pear :: Fruit :: HNil](fruits.unifySubtypes[Apple]) - assertEquals(a :: p :: f :: HNil, fruits.unifySubtypes[Fruit].filter[Fruit]) - - val stuff : Apple :: String :: Pear :: HNil = a :: "foo" :: p :: HNil - typed[Fruit :: String :: Fruit :: HNil](stuff.unifySubtypes[Fruit]) - assertEquals(HNil, stuff.filter[Fruit]) - assertEquals(a :: p :: HNil, stuff.unifySubtypes[Fruit].filter[Fruit]) - } - - @Test - def testToTraversableList: Unit = { - val r1 = HNil.to[List] - assertTypedEquals[List[Nothing]](Nil, r1) - - ToList[HNil, Nothing] - ToList[HNil, Int] - - { - implicitly[ToTraversable.Aux[M[Int] :: HNil, List, M[Int]]] - implicitly[ToTraversable.Aux[M[Int] :: HNil, List, M[_]]] - } - - val r2 = apap.to[List] - assertTypedEquals[List[Fruit]](List(a, p, a, p), r2) - - val fruits2 = apbp.to[List] - assertTypedEquals[List[Fruit]](List(a, p, b, p), fruits2) - - val fruits3 = fruits2.toHList[APBP] - assertTrue(fruits3.isDefined) - assertTypedEquals[APBP](apbp, fruits3.get) - - val stuff = (1 :: "foo" :: 2 :: 3 :: HNil).to[List] - assertTypedEquals[List[Any]](List(1, "foo", 2, 3), stuff) - - val stuff2 = stuff.toHList[ISII] - assertTrue(stuff2.isDefined) - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) - - val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - val l7 = l4 map isDefined - assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) - - val ll2 = l7.to[List] - typed[Boolean](ll2.head) - - val moreStuff = (a :: "foo" :: p :: HNil).to[List] - typed[List[Any]](moreStuff) - - - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val ctv = cicscicicd.to[List] - equalInferredTypes(cicscicicdList, ctv) - assertTypedEquals[List[Ctv[Int with String with Double]]](cicscicicdList, ctv) - - val m = mimsmimimd.to[List] - equalInferredTypes(mimsmimimdList, m) - assertTypedEquals[List[M[_ >: Int with String with Double]]](mimsmimimdList, m) - - val mWithEx = mimsmimemd.to[List] - // equalType(mimsmimemdList, mWithEx) - assertTypedEquals[List[M[_]]](mimsmimemdList, mWithEx) - - val m2 = m2im2sm2im2im2d.to[List] - equalInferredTypes(m2im2sm2im2im2dList, m2) - assertTypedEquals[List[M2[_ >: Int with String with Double, Unit]]](m2im2sm2im2im2dList, m2) - - val m2e = m2eim2esm2eim2eem2ed.to[List] - // equalType(m2eim2esm2eim2eem2edList, m2e) - assertTypedEquals[List[M2[_ >: Int with String with Double, _]]](m2eim2esm2eim2eem2edList, m2e) - } - - @Test - def testToPreciseList: Unit = { - val r1 = HNil.toCoproduct[List] - assertTypedEquals[List[CNil]](Nil, r1) - - val r2 = ap.toCoproduct[List] - assertTypedEquals[List[APc]](List(Coproduct[APc](a), Coproduct[APc](p)), r2) - - val r3 = apap.toCoproduct[List] - assertTypedEquals[List[APc]](List(Coproduct[APc](a), Coproduct[APc](p), Coproduct[APc](a), Coproduct[APc](p)), r3) - - val r4 = apbp.toCoproduct[Vector] - assertTypedEquals[Vector[ABPc]](Vector[ABPc](Coproduct[ABPc](a), Coproduct[ABPc](p), Coproduct[ABPc](b), Coproduct[ABPc](p)), r4) - - def equalInferedCoproducts[A <: Coproduct, B <: Coproduct](a: A, b: B)(implicit bInA: ops.coproduct.Basis[A, B], aInB: ops.coproduct.Basis[B, A]): Unit = {} - val abpc = Coproduct[ABPc](a) - - val r5 = (a :: b :: a :: p :: b :: a :: HNil).toCoproduct[Set] - equalInferedCoproducts(abpc, r5.head) - - val r6 = (p :: a :: a :: p :: p :: b :: HNil).toCoproduct[Set] - equalInferedCoproducts(abpc, r6.head) - - val r7 = (a :: b :: p :: HNil).toCoproduct[Seq] - equalInferedCoproducts(abpc, r7.head) - - - val r8 = (a :: b :: HNil).toCoproduct[Seq] - - illTyped{ - """equalInferedCoproducts(abpc, r8.head)""" - } - - illTyped{ - """(1 :: "foo" :: HNil).toPrecise[Array]""" - } - - } - - @Test - def testToList: Unit = { - val r1 = HNil.toList - assertTypedEquals[List[Nothing]](Nil, r1) - - implicitly[ToTraversable.Aux[HNil, List, Nothing]] - implicitly[ToTraversable.Aux[HNil, List, Int]] - - { - val l1 = (mi :: HNil).toList[M[Int]] - val l2 = (mi :: HNil).toList[M[_]] - - assertTypedEquals[List[M[Int]]](List(mi), l1) - assertTypedEquals[List[M[_]]](List(mi), l2) - } - - val fruits1 = apap.toList - assertTypedEquals[List[Fruit]](List(a, p, a, p), fruits1) - - val fruits2 = apbp.toList - assertTypedEquals[List[Fruit]](List(a, p, b, p), fruits2) - - val fruits3 = fruits2.toHList[APBP] - assertTrue(fruits3.isDefined) - assertTypedEquals[APBP](apbp, fruits3.get) - - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - - val stuff = l1.toList - assertTypedEquals[List[Any]](List(1, "foo", 2, 3), stuff) - - val stuff2 = stuff.toHList[ISII] - assertTrue(stuff2.isDefined) - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) - - val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - val l7 = l4 map isDefined - assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) - - val ll2 = l7.toList - typed[Boolean](ll2.head) - - val moreStuff = (a :: "foo" :: p :: HNil).toList - typed[List[Any]](moreStuff) - - - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val ctv = cicscicicd.toList - equalInferredTypes(cicscicicdList, ctv) - assertTypedEquals[List[Ctv[Int with String with Double]]](cicscicicdList, ctv) - - val m = mimsmimimd.toList - equalInferredTypes(mimsmimimdList, m) - assertTypedEquals[List[M[_ >: Int with String with Double]]](mimsmimimdList, m) - - // With existentials, it gets more tricky - val mWithEx = mimsmimemd.toList - // Compiler fails complaining that it - // Cannot prove that List[HListTests.this.M[_ >: Double with _$1 with Int with String]] =:= List[HListTests.this.M[_]] - // equalType(mimsmimemdList, mWithEx) - assertTypedEquals[List[M[_]]](mimsmimemdList, mWithEx) - - // Second order higher kinded types are ok... - val m2 = m2im2sm2im2im2d.toList - equalInferredTypes(m2im2sm2im2im2dList, m2) - assertTypedEquals[List[M2[_ >: Int with String with Double, Unit]]](m2im2sm2im2im2dList, m2) - - // ...as long as existentials are not involved. - val m2e = m2eim2esm2eim2eem2ed.toList - // Compiler complains that it - // Cannot prove that List[HListTests.this.M2[_ >: Double with Int with Int with String with Int, _ >: _$5 with _$3 with _$3 with _$4 with _$3]] =:= List[HListTests.this.M2[_35,_36] forSome { type _$10; type _$9; type _34 >: _$10 with _$9; type _$8; type _$7; type _32 >: _$8 with _$7; type _35 >: Double with Int with Int with String; type _36 >: _34 with _32 }] - // equalType(m2eim2esm2eim2eem2edList, m2e) - assertTypedEquals[List[M2[_ >: Int with String with Double, _]]](m2eim2esm2eim2eem2edList, m2e) - } - - @Test - def testToTraversableArray: Unit = { - def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = - assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) - - val empty = HNil.to[Array] - typed[Array[Nothing]](empty) - assertArrayEquals2(Array[Nothing](), empty) - - implicitly[ToTraversable.Aux[HNil, Array, Nothing]] - implicitly[ToTraversable.Aux[HNil, Array, Int]] - - { - implicitly[ToTraversable.Aux[M[Int] :: HNil, Array, M[Int]]] - implicitly[ToTraversable.Aux[M[Int] :: HNil, Array, M[_]]] - } - - val fruits1 = apap.to[Array].map(x => x : Fruit) // Default inferred type is too precise - // (Product with Serializable with Fruit) - typed[Array[Fruit]](fruits1) - assertArrayEquals2(Array[Fruit](a, p, a, p), fruits1) - - val fruits2 = apbp.to[Array].map(x => x : Fruit) - typed[Array[Fruit]](fruits2) - assertArrayEquals2(Array[Fruit](a, p, b, p), fruits2) - - val fruits3 = fruits2.toHList[APBP] - assertTrue(fruits3.isDefined) - assertTypedEquals[APBP](apbp, fruits3.get) - - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - - val stuff = l1.to[Array] - typed[Array[Any]](stuff) - assertArrayEquals2(Array(1, "foo", 2, 3), stuff) - - val stuff2 = stuff.toHList[ISII] - assertTrue(stuff2.isDefined) - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) - - val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - val l7 = l4 map isDefined - assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) - - val ll2 = l7.to[Array] - typed[Boolean](ll2(0)) - - val moreStuff = (a :: "foo" :: p :: HNil).to[Array].map(x => x : AnyRef) - typed[Array[AnyRef]](moreStuff) - assertArrayEquals2(Array[AnyRef](a, "foo", p), moreStuff) - - - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val ctv = cicscicicd.to[Array] - equalInferredTypes(cicscicicdArray, ctv) - typed[Array[Ctv[Int with String with Double]]](ctv) - assertArrayEquals2(cicscicicdArray, ctv) - - val m = mimsmimimd.to[Array] - equalInferredTypes(mimsmimimdArray, m) - typed[Array[MIntStringDoubleBound]](m) - assertArrayEquals2(mimsmimimdArray, m) - - val mWithEx = mimsmimemd.to[Array] - // equalType(mimsmimemdArray, mWithEx) - typed[Array[M[_]]](mWithEx) - assertArrayEquals2(mimsmimemdArray, mWithEx) - - val m2 = m2im2sm2im2im2d.to[Array] - equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2IntStringDoubleBound[Unit]]](m2) - assertArrayEquals2(m2im2sm2im2im2dArray, m2) - - val m2e = m2eim2esm2eim2eem2ed.to[Array] - // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2IntStringDoubleBound[_]]](m2e) - assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) - } - - @Test - def testToArray: Unit = { - def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = - assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) - - val empty = HNil.toArray - typed[Array[Nothing]](empty) - assertArrayEquals2(Array[Nothing](), empty) - - ToArray[HNil, Nothing] - ToArray[HNil, Int] - - { - val a1 = (mi :: HNil).toArray[M[Int]] - val a2 = (mi :: HNil).toArray[M[_]] - - typed[Array[M[Int]]](a1) - typed[Array[M[_]]](a2) - assertArrayEquals2(Array[M[Int]](mi), a1) - assertArrayEquals2(Array[M[_]](mi), a2) - } - - val fruits1 = apap.toArray[Fruit] - typed[Array[Fruit]](fruits1) - assertArrayEquals2(Array[Fruit](a, p, a, p), fruits1) - - val fruits2 = apbp.toArray[Fruit] - typed[Array[Fruit]](fruits2) - assertArrayEquals2(Array[Fruit](a, p, b, p), fruits2) - - val fruits3 = fruits2.toHList[APBP] - assertTrue(fruits3.isDefined) - assertTypedEquals[APBP](apbp, fruits3.get) - - val l1 = 1 :: "foo" :: 2 :: 3 :: HNil - - val stuff = l1.toArray - typed[Array[AnyOrMatchable]](stuff) - assertArrayEquals2(Array(1, "foo", 2, 3), stuff) - - val ssl = "foo" :: "bar" :: 1L :: HNil - val ssla = ssl.toArray - typed[Array[AnyOrMatchable]](ssla) - assertArrayEquals2(Array("foo", "bar", 1L), ssla) - - val stuff2 = stuff.toHList[ISII] - assertTrue(stuff2.isDefined) - assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) - - val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - val l7 = l4 map isDefined - assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) - - val ll2 = l7.toArray - typed[Boolean](ll2(0)) - - val moreStuff = (a :: "foo" :: p :: HNil).toArray[AnyRef] - typed[Array[AnyRef]](moreStuff) - assertArrayEquals2(Array[AnyRef](a, "foo", p), moreStuff) - - - def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} - - val ctv = cicscicicd.toArray - equalInferredTypes(cicscicicdArray, ctv) - typed[Array[Ctv[Int with String with Double]]](ctv) - assertArrayEquals2(cicscicicdArray, ctv) - - val m = mimsmimimd.toArray - equalInferredTypes(mimsmimimdArray, m) - typed[Array[MIntStringDoubleBound]](m) - assertArrayEquals2(mimsmimimdArray, m) - - val mWithEx = mimsmimemd.toArray[M[_]] - // equalType(mimsmimemdArray, mWithEx) - typed[Array[M[_]]](mWithEx) - assertArrayEquals2(mimsmimemdArray, mWithEx) - - val m2 = m2im2sm2im2im2d.toArray - equalInferredTypes(m2im2sm2im2im2dArray, m2) - typed[Array[M2IntStringDoubleBound[Unit]]](m2) - assertArrayEquals2(m2im2sm2im2im2dArray, m2) - - val m2e = m2eim2esm2eim2eem2ed.toArray - // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) - typed[Array[M2IntStringDoubleBound[_]]](m2e) - assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) - } - - @Test - def testFoldMap: Unit = { - implicitly[Mapper.Aux[isDefined.type, HNil, HNil]] - implicitly[Mapper.Aux[isDefined.type, Option[Int] :: HNil, Boolean :: HNil]] - - val tl1 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil - val tl2 = Option(1) :: Option("foo") :: (None : Option[Int]) :: Option(3) :: HNil - - val mlfl1 = (tl1 map isDefined).toList.foldLeft(true)(_ && _) - assertTrue(mlfl1) - val mlfl2 = (tl2 map isDefined).toList.foldLeft(true)(_ && _) - assertFalse(mlfl2) - - val fl1 = tl1.foldMap(true)(isDefined)(_ && _) - assertTrue(fl1) - val fl2 = tl2.foldMap(true)(isDefined)(_ && _) - assertFalse(fl2) - } - - @Test - def testAt: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val at0 = sn1(_0) - assertTypedEquals[Int](23, at0) - - val at1 = sn1(_1) - typed[Double](at1) - assertEquals(3.0, at1, Double.MinPositiveValue) - - val at2 = sn1(_2) - assertTypedEquals[String]("foo", at2) - - val at3 = sn1(_3) - assertTypedEquals[Unit]((), at3) - - val at4 = sn1(_4) - assertTypedEquals[String]("bar", at4) - - val at5 = sn1(_5) - assertTypedEquals[Boolean](true, at5) - - val at6 = sn1(_6) - assertTypedEquals[Long](5L, at6) - - val sn2 = - 0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: - 10 :: 11 :: 12 :: 13 :: 14 :: 15 :: 16 :: 17 :: 18 :: 19 :: - 20 :: 21 :: 22 :: HNil - - val at22 = sn2(_22) - assertTypedEquals[Int](22, at22) - } - - @Test - def testAtLiteral: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val at0 = sn1(0) - assertTypedEquals[Int](23, at0) - - val at1 = sn1(1) - typed[Double](at1) - assertEquals(3.0, at1, Double.MinPositiveValue) - - val at2 = sn1(2) - assertTypedEquals[String]("foo", at2) - - val at3 = sn1(3) - assertTypedEquals[Unit]((), at3) - - val at4 = sn1(4) - assertTypedEquals[String]("bar", at4) - - val at5 = sn1(5) - assertTypedEquals[Boolean](true, at5) - - val at6 = sn1(6) - assertTypedEquals[Long](5L, at6) - - val sn2 = - 0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: - 10 :: 11 :: 12 :: 13 :: 14 :: 15 :: 16 :: 17 :: 18 :: 19 :: - 20 :: 21 :: 22 :: HNil - - val at22 = sn2(22) - assertTypedEquals[Int](22, at22) - } - - @Test - def testTakeDrop: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val r1 = sn1.take(_0) - assertTypedEquals[HNil](HNil, r1) - - val r2 = sn1.drop(_0) - assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( - 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r2) - - val r3 = sn1.take(_2) - assertTypedEquals[Int :: Double :: HNil](23 :: 3.0 :: HNil, r3) - - val r4 = sn1.drop(_2) - assertTypedEquals[String :: Unit :: String :: Boolean :: Long :: HNil]( - "foo" :: () :: "bar" :: true :: 5L :: HNil, r4) - - val r5 = sn1.take(_7) - assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( - 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r5) - - val r6 = sn1.drop(_7) - assertTypedEquals[HNil](HNil, r6) - } - - @Test - def testTakeDropLiteral: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val r1 = sn1.take(0) - assertTypedEquals[HNil](HNil, r1) - - val r2 = sn1.drop(0) - assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( - 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r2) - - val r3 = sn1.take(2) - assertTypedEquals[Int :: Double :: HNil](23 :: 3.0 :: HNil, r3) - - val r4 = sn1.drop(2) - assertTypedEquals[String :: Unit :: String :: Boolean :: Long :: HNil]( - "foo" :: () :: "bar" :: true :: 5L :: HNil, r4) - - val r5 = sn1.take(7) - assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( - 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r5) - - val r6 = sn1.drop(7) - assertTypedEquals[HNil](HNil, r6) - } - - @Test - def testSplit: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val sni0 = sn1.split(_0) - typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni0) - val sni1 = sn1.split(_1) - typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni1) - val sni2 = sn1.split(_2) - typed[((Int :: Double :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](sni2) - val sni3 = sn1.split(_3) - typed[((Int :: Double :: String :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](sni3) - val sni4 = sn1.split(_4) - typed[((Int :: Double :: String :: Unit :: HNil), (String :: Boolean :: Long :: HNil))](sni4) - val sni5 = sn1.split(_5) - typed[((Int :: Double :: String :: Unit :: String :: HNil), (Boolean :: Long :: HNil))](sni5) - val sni6 = sn1.split(_6) - typed[((Int :: Double :: String :: Unit :: String :: Boolean :: HNil), (Long :: HNil))](sni6) - val sni7 = sn1.split(_7) - typed[((Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil), HNil)](sni7) - - val snri0 = sn1.reverse_split(_0) - typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri0) - val snri1 = sn1.reverse_split(_1) - typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri1) - val snri2 = sn1.reverse_split(_2) - typed[((Double :: Int :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](snri2) - val snri3 = sn1.reverse_split(_3) - typed[((String :: Double :: Int :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](snri3) - val snri4 = sn1.reverse_split(_4) - typed[((Unit :: String :: Double :: Int :: HNil), (String :: Boolean :: Long :: HNil))](snri4) - val snri5 = sn1.reverse_split(_5) - typed[((String :: Unit :: String :: Double :: Int :: HNil), (Boolean :: Long :: HNil))](snri5) - val snri6 = sn1.reverse_split(_6) - typed[((Boolean :: String :: Unit :: String :: Double :: Int :: HNil), (Long :: HNil))](snri6) - val snri7 = sn1.reverse_split(_7) - typed[((Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil), HNil)](snri7) - } - - @Test - def testSplitLiteral: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val sni0 = sn1.split(0) - typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni0) - val sni1 = sn1.split(1) - typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni1) - val sni2 = sn1.split(2) - typed[((Int :: Double :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](sni2) - val sni3 = sn1.split(3) - typed[((Int :: Double :: String :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](sni3) - val sni4 = sn1.split(4) - typed[((Int :: Double :: String :: Unit :: HNil), (String :: Boolean :: Long :: HNil))](sni4) - val sni5 = sn1.split(5) - typed[((Int :: Double :: String :: Unit :: String :: HNil), (Boolean :: Long :: HNil))](sni5) - val sni6 = sn1.split(6) - typed[((Int :: Double :: String :: Unit :: String :: Boolean :: HNil), (Long :: HNil))](sni6) - val sni7 = sn1.split(7) - typed[((Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil), HNil)](sni7) - - val snri0 = sn1.reverse_split(0) - typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri0) - val snri1 = sn1.reverse_split(1) - typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri1) - val snri2 = sn1.reverse_split(2) - typed[((Double :: Int :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](snri2) - val snri3 = sn1.reverse_split(3) - typed[((String :: Double :: Int :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](snri3) - val snri4 = sn1.reverse_split(4) - typed[((Unit :: String :: Double :: Int :: HNil), (String :: Boolean :: Long :: HNil))](snri4) - val snri5 = sn1.reverse_split(5) - typed[((String :: Unit :: String :: Double :: Int :: HNil), (Boolean :: Long :: HNil))](snri5) - val snri6 = sn1.reverse_split(6) - typed[((Boolean :: String :: Unit :: String :: Double :: Int :: HNil), (Long :: HNil))](snri6) - val snri7 = sn1.reverse_split(7) - typed[((Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil), HNil)](snri7) - } - - @Test - def testSplitP: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val sni0 = sn1.splitP(_0) - typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni0) - val sni1 = sn1.splitP(_1) - typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni1) - val sni2 = sn1.splitP(_2) - typed[(Int :: Double :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni2) - val sni3 = sn1.splitP(_3) - typed[(Int :: Double :: String :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni3) - val sni4 = sn1.splitP(_4) - typed[(Int :: Double :: String :: Unit :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](sni4) - val sni5 = sn1.splitP(_5) - typed[(Int :: Double :: String :: Unit :: String :: HNil) :: (Boolean :: Long :: HNil) :: HNil](sni5) - val sni6 = sn1.splitP(_6) - typed[(Int :: Double :: String :: Unit :: String :: Boolean :: HNil) :: (Long :: HNil) :: HNil](sni6) - val sni7 = sn1.splitP(_7) - typed[(Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: (HNil) :: HNil](sni7) - - val snri0 = sn1.reverse_splitP(_0) - typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri0) - val snri1 = sn1.reverse_splitP(_1) - typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri1) - val snri2 = sn1.reverse_splitP(_2) - typed[(Double :: Int :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri2) - val snri3 = sn1.reverse_splitP(_3) - typed[(String :: Double :: Int :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri3) - val snri4 = sn1.reverse_splitP(_4) - typed[(Unit :: String :: Double :: Int :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](snri4) - val snri5 = sn1.reverse_splitP(_5) - typed[(String :: Unit :: String :: Double :: Int :: HNil) :: (Boolean :: Long :: HNil) :: HNil](snri5) - val snri6 = sn1.reverse_splitP(_6) - typed[(Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (Long :: HNil) :: HNil](snri6) - val snri7 = sn1.reverse_splitP(_7) - typed[(Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (HNil) :: HNil](snri7) - } - - @Test - def testSplitPLiteral: Unit = { - val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val sni0 = sn1.splitP(0) - typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni0) - val sni1 = sn1.splitP(1) - typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni1) - val sni2 = sn1.splitP(2) - typed[(Int :: Double :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni2) - val sni3 = sn1.splitP(3) - typed[(Int :: Double :: String :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni3) - val sni4 = sn1.splitP(4) - typed[(Int :: Double :: String :: Unit :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](sni4) - val sni5 = sn1.splitP(5) - typed[(Int :: Double :: String :: Unit :: String :: HNil) :: (Boolean :: Long :: HNil) :: HNil](sni5) - val sni6 = sn1.splitP(6) - typed[(Int :: Double :: String :: Unit :: String :: Boolean :: HNil) :: (Long :: HNil) :: HNil](sni6) - val sni7 = sn1.splitP(7) - typed[(Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: (HNil) :: HNil](sni7) - - val snri0 = sn1.reverse_splitP(0) - typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri0) - val snri1 = sn1.reverse_splitP(1) - typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri1) - val snri2 = sn1.reverse_splitP(2) - typed[(Double :: Int :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri2) - val snri3 = sn1.reverse_splitP(3) - typed[(String :: Double :: Int :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri3) - val snri4 = sn1.reverse_splitP(4) - typed[(Unit :: String :: Double :: Int :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](snri4) - val snri5 = sn1.reverse_splitP(5) - typed[(String :: Unit :: String :: Double :: Int :: HNil) :: (Boolean :: Long :: HNil) :: HNil](snri5) - val snri6 = sn1.reverse_splitP(6) - typed[(Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (Long :: HNil) :: HNil](snri6) - val snri7 = sn1.reverse_splitP(7) - typed[(Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (HNil) :: HNil](snri7) - } - - @Test - def testSelect: Unit = { - val sl = 1 :: true :: "foo" :: 2.0 :: HNil - val si = sl.select[Int] - assertTypedEquals[Int](1, si) - - val sb = sl.select[Boolean] - assertTypedEquals[Boolean](true, sb) - - val ss = sl.select[String] - assertTypedEquals[String]("foo", ss) - - val sd = sl.select[Double] - assertEquals(2.0, sd, Double.MinPositiveValue) - } - @Test - def testSelectRange: Unit = { - val sl = 1 :: true :: "foo" :: 2.0 :: HNil - - val sl1 = sl.selectRange[_0,_0] - val sl1i = sl.selectRange(0,0) - assertTypedEquals[HNil](HNil, sl1) - assertTypedEquals[HNil](HNil, sl1i) - - val sl2 = sl.selectRange[_1,_1] - val sl2i = sl.selectRange(1,1) - assertTypedEquals[HNil](HNil, sl2) - assertTypedEquals[HNil](HNil, sl2i) - - val sl3 = sl.selectRange[_0,_2] - val sl3i = sl.selectRange(0,2) - assertTypedEquals[Int::Boolean::HNil](1::true::HNil, sl3) - assertTypedEquals[Int::Boolean::HNil](1::true::HNil, sl3i) - - val sl4 = sl.selectRange[_2,_4] - val sl4i = sl.selectRange(2,4) - assertTypedEquals[String::Double::HNil]("foo"::2.0::HNil, sl4) - assertTypedEquals[String::Double::HNil]("foo"::2.0::HNil, sl4i) - - val sl5 = sl.selectRange[_0,_4] - val sl5i = sl.selectRange(0,4) - assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, sl5) - assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, sl5i) - - } - - @Test - def testSelectFirst: Unit = { - val sl = 1 :: true :: "foo" :: 2.0 :: HNil - - val si = sl.selectFirst[Int::HNil] - assertTypedEquals[Int](1, si) - - val sb = sl.selectFirst[Boolean::HNil] - assertTypedEquals[Boolean](true, sb) - - val ss = sl.selectFirst[String::HNil] - assertTypedEquals[String]("foo", ss) - - val sd = sl.selectFirst[Double::HNil] - assertEquals(2.0, sd, Double.MinPositiveValue) - - val sib = sl.selectFirst[Int::Boolean::HNil] - assertTypedEquals[Int](1, sib) - - val sulb = sl.selectFirst[Unit::Long::Boolean::HNil] - assertTypedEquals[Boolean](true, sulb) - - val ssbi = sl.selectFirst[String::Boolean::Int::HNil] - assertTypedEquals[String]("foo", ssbi) - } - - @Test - def testFilter: Unit = { - val l1 = 1 :: 2 :: HNil - val f1 = l1.filter[Int] - assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f1) - - val l2 = 1 :: true :: "foo" :: 2 :: HNil - val f2 = l2.filter[Int] - assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f2) - - typed[HNil](l2.filter[Double]) - } - - @Test - def testFilterNot: Unit = { - val l1 = 1 :: 2 :: HNil - val f1 = l1.filterNot[String] - assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f1) - - val l2 = 1 :: true :: "foo" :: 2 :: HNil - val f2 = l2.filterNot[String] - assertTypedEquals[Int :: Boolean :: Int :: HNil](1 :: true :: 2 :: HNil, f2) - - typed[HNil](l2.filter[Double]) - } - - @Test - def testPartition: Unit = { - val l1 = 1 :: 2 :: HNil - val l2 = 1 :: true :: "foo" :: 2 :: HNil - - val r1 = l1.partition[Int] - assertTypedEquals[(Int :: Int :: HNil, HNil)]((1 :: 2 :: HNil, HNil), r1) - - val r2 = l1.partitionP[Int] - assertTypedEquals[(Int :: Int :: HNil) :: HNil :: HNil]((1 :: 2 :: HNil) :: HNil :: HNil, r2) - - val r3 = l2.partition[Int] - assertTypedEquals[(Int :: Int :: HNil, Boolean :: String :: HNil)]((1 :: 2 :: HNil, true :: "foo" :: HNil), r3) - - val r4 = l2.partitionP[Int] - assertTypedEquals[(Int :: Int :: HNil) :: (Boolean :: String :: HNil) :: HNil]( - (1 :: 2 :: HNil) :: (true :: "foo" :: HNil) :: HNil, r4 - ) - } - - @Test - def testReplace: Unit = { - val sl = 1 :: true :: "foo" :: 2.0 :: HNil - - val (i, r1) = sl.replace(23) - assertTypedEquals[Int](1, i) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](23 :: true :: "foo" :: 2.0 :: HNil, r1) - - val (b, r2) = sl.replace(false) - assertTypedEquals[Boolean](true, b) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: false :: "foo" :: 2.0 :: HNil, r2) - - val (s, r3) = sl.replace("bar") - assertTypedEquals[String]("foo", s) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "bar" :: 2.0 :: HNil, r3) - - val (d, r4) = sl.replace(3.0) - typed[Double](d) - assertEquals(2.0, d, Double.MinPositiveValue) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "foo" :: 3.0 :: HNil, r4) - - val (i2, r5) = sl.replaceType[Int]('*') - typed[Char](r5(0)) - assertTypedEquals[Int](1, i2) - assertTypedEquals[Char :: Boolean :: String :: Double :: HNil]('*' :: true :: "foo" :: 2.0 :: HNil, r5) - - val (b2, r6) = sl.replaceType[Boolean]('*') - typed[Char](r6(1)) - assertTypedEquals[Boolean](true, b2) - assertTypedEquals[Int :: Char :: String :: Double :: HNil](1 :: '*' :: "foo" :: 2.0 :: HNil, r6) - - val (s2, r7) = sl.replaceType[String]('*') - typed[Char](r7(2)) - assertTypedEquals[String]("foo", s2) - assertTypedEquals[Int :: Boolean :: Char :: Double :: HNil](1 :: true :: '*' :: 2.0 :: HNil, r7) - - val (d2, r8) = sl.replaceType[Double]('*') - typed[Double](d2) - typed[Char](r8(3)) - assertEquals(2.0, d2, Double.MinPositiveValue) - assertTypedEquals[Int :: Boolean :: String :: Char :: HNil](1 :: true :: "foo" :: '*' :: HNil, r8) - - val fruits = a :: p :: a :: f :: HNil - val (x1, rr1) = fruits.replaceType[Pear](a) - typed[Pear](x1) - typed[Apple :: Apple :: Apple :: Fruit :: HNil](rr1) - - val (x2, rr2) = fruits.replaceType[Pear](f) - typed[Pear](x2) - typed[Apple :: Fruit :: Apple :: Fruit :: HNil](rr2) - - val (x3, rr3) = fruits.replaceType[Fruit](p) - typed[Fruit](x3) - typed[Apple :: Pear :: Apple :: Pear :: HNil](rr3) - - val (x4, rr4) = fruits.replace(p) - typed[Pear](x4) - typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr4) - - val (x5, rr5) = fruits.replace(f) - typed[Fruit](x5) - typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr5) - } - - @Test - def testUpdate: Unit = { - type SL = Int :: Boolean :: String :: Double :: HNil - val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil - - val r1 = sl.updatedElem(23) - assertTypedEquals[SL](23 :: true :: "foo" :: 2.0 :: HNil, r1) - - val r2 = sl.updatedElem(false) - assertTypedEquals[SL](1 :: false :: "foo" :: 2.0 :: HNil, r2) - - val r3 = sl.updatedElem("bar") - assertTypedEquals[SL](1 :: true :: "bar" :: 2.0 :: HNil, r3) - - val r4 = sl.updatedElem(3.0) - assertTypedEquals[SL](1 :: true :: "foo" :: 3.0 :: HNil, r4) - - val r5 = sl.updatedType[Int]('*') - assertTypedEquals[Char :: Boolean :: String :: Double :: HNil]('*' :: true :: "foo" :: 2.0 :: HNil, r5) - - val r6 = sl.updatedType[Boolean]('*') - assertTypedEquals[Int :: Char :: String :: Double :: HNil](1 :: '*' :: "foo" :: 2.0 :: HNil, r6) - - val r7 = sl.updatedType[String]('*') - assertTypedEquals[Int :: Boolean :: Char :: Double :: HNil](1 :: true :: '*' :: 2.0 :: HNil, r7) - - val r8 = sl.updatedType[Double]('*') - assertTypedEquals(1 :: true :: "foo" :: '*' :: HNil, r8) - - val r9 = sl.updateWith((i : Int) => i * 2) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](2 :: true :: "foo" :: 2.0 :: HNil, r9) - - val r10 = sl.updateWith((b : Boolean) => !b) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: false :: "foo" :: 2.0 :: HNil, r10) - - val r11 = sl.updateWith((s : String) => s.toUpperCase) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "FOO" :: 2.0 :: HNil, r11) - - val r12 = sl.updateWith((d : Double) => d / 2.0) - assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "foo" :: 1.0 :: HNil, r12) - - val r13 = sl.updateWith((i : Int) => i.toString) - assertTypedEquals[String :: Boolean :: String :: Double :: HNil]("1" :: true :: "foo" :: 2.0 :: HNil, r13) - - val r14 = sl.updateWith((b : Boolean) => b.toString) - assertTypedEquals[Int :: String :: String :: Double :: HNil](1 :: "true" :: "foo" :: 2.0 :: HNil, r14) - - val r15 = sl.updateWith((_ : String) => 0xF00) - assertTypedEquals[Int :: Boolean :: Int :: Double :: HNil](1 :: true :: 0xF00 :: 2.0 :: HNil, r15) - - val r16 = sl.updateWith((d : Double) => d.toString) - assertTypedEquals[Int :: Boolean :: String :: String :: HNil](1 :: true :: "foo" :: 2.0.toString :: HNil, r16) - - val fruits = a :: p :: a :: f :: HNil - - val rr1 = fruits.updatedType[Pear](a) - typed[Apple :: Apple :: Apple :: Fruit :: HNil](rr1) - - val rr2 = fruits.updatedType[Pear](f) - typed[Apple :: Fruit :: Apple :: Fruit :: HNil](rr2) - - val rr3 = fruits.updatedType[Fruit](p) - typed[Apple :: Pear :: Apple :: Pear :: HNil](rr3) - - val rr4 = fruits.updatedElem(p) - typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr4) - - val rr5 = fruits.updatedElem(f) - typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr5) - } - - @Test - def testSplitLeft: Unit = { - type SL = Int :: Boolean :: String :: Double :: HNil - type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil - val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil - val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val (sp1, sp2) = sl.splitLeft[String] - typed[String :: Double :: HNil](sp2) - typed[Int :: Boolean :: HNil](sp1) - assertTypedEquals[SL]((sp1 ::: sp2), sl) - - val (sli1, sli2) = sl2.splitLeft[String] - typed[Int :: Double :: HNil](sli1) - typed[String :: Unit :: String :: Boolean :: Long :: HNil](sli2) - assertTypedEquals[SL2]((sli1 ::: sli2), sl2) - - val (rsp1, rsp2) = sl.reverse_splitLeft[String] - typed[Boolean :: Int :: HNil](rsp1) - typed[String :: Double :: HNil](rsp2) - assertTypedEquals[SL]((rsp1 reverse_::: rsp2), sl) - - val (rsli1, rsli2) = sl2.reverse_splitLeft[String] - typed[Double :: Int :: HNil](rsli1) - typed[String :: Unit :: String :: Boolean :: Long :: HNil](rsli2) - assertTypedEquals[SL2]((rsli1 reverse_::: rsli2), sl2) - } - - @Test - def testSplitLeftP: Unit = { - type SL = Int :: Boolean :: String :: Double :: HNil - type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil - val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil - val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val sp1 :: sp2 :: HNil = sl.splitLeftP[String] - typed[String :: Double :: HNil](sp2) - typed[Int :: Boolean :: HNil](sp1) - assertTypedEquals[SL]((sp1 ::: sp2), sl) - - val sli1 :: sli2 :: HNil = sl2.splitLeftP[String] - typed[Int :: Double :: HNil](sli1) - typed[String :: Unit :: String :: Boolean :: Long :: HNil](sli2) - assertTypedEquals[SL2]((sli1 ::: sli2), sl2) - - val rsp1 :: rsp2 :: HNil = sl.reverse_splitLeftP[String] - typed[Boolean :: Int :: HNil](rsp1) - typed[String :: Double :: HNil](rsp2) - assertTypedEquals[SL]((rsp1 reverse_::: rsp2), sl) - - val rsli1 :: rsli2 :: HNil = sl2.reverse_splitLeftP[String] - typed[Double :: Int :: HNil](rsli1) - typed[String :: Unit :: String :: Boolean :: Long :: HNil](rsli2) - assertTypedEquals[SL2]((rsli1 reverse_::: rsli2), sl2) - } - - @Test - def testSplitRight: Unit = { - type SL = Int :: Boolean :: String :: Double :: HNil - type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil - val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil - val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val (srp1, srp2) = sl.splitRight[String] - typed[Int :: Boolean :: String :: HNil](srp1) - typed[Double :: HNil](srp2) - assertTypedEquals[SL]((srp1 ::: srp2), sl) - - val (srli1, srli2) = sl2.splitRight[String] - typed[Int :: Double :: String :: Unit :: String :: HNil](srli1) - typed[Boolean :: Long :: HNil](srli2) - assertTypedEquals[SL2](sl2, srli1 ::: srli2) - - val (rsrp1, rsrp2) = sl.reverse_splitRight[String] - typed[String :: Boolean :: Int :: HNil](rsrp1) - typed[Double :: HNil](rsrp2) - assertTypedEquals[SL]((rsrp1 reverse_::: rsrp2), sl) - - val (rsrli1, rsrli2) = sl2.reverse_splitRight[String] - typed[String :: Unit :: String :: Double :: Int :: HNil](rsrli1) - typed[Boolean :: Long :: HNil](rsrli2) - assertTypedEquals[SL2]((rsrli1 reverse_::: rsrli2), sl2) - } - - @Test - def testSplitRightP: Unit = { - type SL = Int :: Boolean :: String :: Double :: HNil - type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil - val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil - val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val srp1 :: srp2 :: HNil = sl.splitRightP[String] - typed[Int :: Boolean :: String :: HNil](srp1) - typed[Double :: HNil](srp2) - assertTypedEquals[SL]((srp1 ::: srp2), sl) - - val srli1 :: srli2 :: HNil = sl2.splitRightP[String] - typed[Int :: Double :: String :: Unit :: String :: HNil](srli1) - typed[Boolean :: Long :: HNil](srli2) - assertTypedEquals[SL2](sl2, srli1 ::: srli2) - - val rsrp1 :: rsrp2 :: HNil = sl.reverse_splitRightP[String] - typed[String :: Boolean :: Int :: HNil](rsrp1) - typed[Double :: HNil](rsrp2) - assertTypedEquals[SL]((rsrp1 reverse_::: rsrp2), sl) - - val rsrli1 :: rsrli2 :: HNil = sl2.reverse_splitRightP[String] - typed[String :: Unit :: String :: Double :: Int :: HNil](rsrli1) - typed[Boolean :: Long :: HNil](rsrli2) - assertTypedEquals[SL2]((rsrli1 reverse_::: rsrli2), sl2) - } - - @Test - def testTranspose: Unit = { - val l1 = 1 :: HNil - val l2 = ("a" :: HNil) :: HNil - - val r1 = l1.zipOne(l2) - assertTypedEquals[(Int :: String :: HNil) :: HNil]((1 :: "a" :: HNil) :: HNil, r1) - val r2 = l1.mapConst(HNil) - assertTypedEquals[HNil :: HNil](HNil :: HNil, r2) - val r3 = (l1 :: HNil).transpose - assertTypedEquals[(Int :: HNil) :: HNil]((1 :: HNil) :: HNil, r3) - - val l3 = 1 :: 2 :: 3 :: HNil - val l4 = ("a" :: 1.0 :: HNil) :: ("b" :: 2.0 :: HNil) :: ("c" :: 3.0 :: HNil) :: HNil - - type ISD = Int :: String :: Double :: HNil - val z2 = l3.zipOne(l4) - assertTypedEquals[ISD :: ISD :: ISD :: HNil]( - (1 :: "a" :: 1.0 :: HNil) :: (2 :: "b" :: 2.0 :: HNil) :: (3 :: "c" :: 3.0 :: HNil) :: HNil, z2 - ) - - val r5 = l3.mapConst(HNil) - assertTypedEquals[HNil :: HNil :: HNil :: HNil](HNil :: HNil :: HNil :: HNil, r5) - - val t2 = l4.transpose - assertTypedEquals[ - (String :: String :: String :: HNil) :: - (Double :: Double :: Double :: HNil) :: HNil - ](("a" :: "b" :: "c" :: HNil) :: (1.0 :: 2.0 :: 3.0 :: HNil) :: HNil, t2) - - val t3 = z2.transpose - assertTypedEquals[ - (Int :: Int :: Int :: HNil) :: - (String :: String :: String :: HNil) :: - (Double :: Double :: Double :: HNil) :: HNil - ]( - (1 :: 2 :: 3 :: HNil) :: - ("a" :: "b" :: "c" :: HNil) :: - (1.0 :: 2.0 :: 3.0 :: HNil) :: HNil, - t3 - ) - - val r8 = t3.transpose - assertTypedEquals[ISD :: ISD :: ISD :: HNil](z2, r8) - - val nil: HNil = HNil - - val r9 = nil zipOne nil - assertTypedEquals[HNil](HNil, r9) - - val r10 = nil.transpose - assertTypedEquals[HNil](HNil, r10) - - val r11 = (HNil :: HNil :: HNil : HNil :: HNil :: HNil).transpose - assertTypedEquals[HNil](HNil, r11) - - val r12 = (1 :: HNil) zipOne ((2 :: HNil) :: HNil) - assertTypedEquals[(Int :: Int :: HNil) :: HNil]((1 :: 2 :: HNil) :: HNil, r12) - } - - @Test - def testZipUnzip: Unit = { - val l1 = 1 :: "a" :: 1.0 :: HNil - val l2 = 2 :: "b" :: 2.0 :: HNil - - val t1 = (l1 :: l2 :: HNil).transpose - val z1 = t1.map(tupled) - assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( - (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z1) - - def zip[L <: HList, OutT <: HList](l : L) - (implicit - transposer : Transposer.Aux[L, OutT], - mapper : Mapper[tupled.type, OutT]) = l.transpose.map(tupled) - - val z2 = zip(l1 :: l2 :: HNil) - assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( - (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z2) - - val z3 = (l1 :: l2 :: HNil).zip - assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( - (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z3) - - val nil : HNil = HNil - val z4 = (nil :: nil :: HNil).zip - assertTypedEquals[HNil](nil, z4) - - val t2 = z1.map(productElements).transpose - val u1 = t2.tupled - assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( - (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), u1) - - def unzip[L <: HList, OutM <: HList, OutT <: HList](l : L) - (implicit - mapper : Mapper.Aux[productElements.type, L, OutM], - transposer : Transposer.Aux[OutM, OutT], - tupler : Tupler[OutT]) = l.map(productElements).transpose.tupled - - val u2 = unzip(z1) - assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( - (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), u2) - - val r1 = z1.unzip - assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( - (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), r1) - - val r2 = l1 zip l2 - assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( - (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, r2) - - val intInc : Int => Int = _+1 - val stringInc : String => String = _+"*" - val doubleInc : Double => Int = _.toInt+1 - - val l3 = intInc :: stringInc :: doubleInc :: HNil - - val z5 = l3 zipApply l1 - assertTypedEquals[Int :: String :: Int :: HNil](2 :: "a*" :: 2 :: HNil, z5) - } - - @Test - def testUnapply: Unit = { - val l = 1 :: true :: "foo" :: 2.0 :: HNil - val l2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil - - val is = l match { - case i :: true :: s :: 2.0 :: HNil => (i, s) - case _ => sys.error("Not matched") - } - - assertTypedEquals[Int](1, is._1) - assertTypedEquals[String]("foo", is._2) - - val is2 = (l : Any) match { - case (i : Int) :: true :: (s : String) :: 2.0 :: HNil => (i, s) - case _ => sys.error("Not matched") - } - - assertTypedEquals[Int](1, is2._1) - assertTypedEquals[String]("foo", is2._2) - - import HList.ListCompat._ - - val tl = l2 match { - case 23 #: 3.0 #: s #: xs => (s, xs) - case _ => sys.error("Not matched") - } - - assertTypedEquals[String]("foo", tl._1) - assertTypedEquals[Unit :: String :: Boolean :: Long :: HNil](() :: "bar" :: true :: 5L :: HNil, tl._2) - - val tl2 = (l2 : Any) match { - case 23 #: 3.0 #: (s : String) #: xs => (s, xs) - case _ => sys.error("Not matched") - } - - assertTypedEquals[String]("foo", tl2._1) - assertTypedEquals[HList](() :: "bar" :: true :: 5L :: HNil, tl2._2) - - val ll = List(1, 2, 3, 4) - val tll = ll match { - case 1 :: 2 :: x :: y :: Nil => (x, y) - case _ => sys.error("Not matched") - } - assertTypedEquals[Int](3, tll._1) - assertTypedEquals[Int](4, tll._2) - - val tll2 = ll match { - case 1 :: xs => xs - case _ => sys.error("Not matched") - } - assertTypedEquals[List[Int]](List(2, 3, 4), tll2) - - val mixed = 23 :: "foo" :: (1 :: 2 :: 3 :: 4 :: 5 :: Nil) :: false :: () :: HNil - val tmixed = mixed match { - case _ #: _ #: (_ :: 2 :: x :: tl1) #: tl2 => (x, tl1, tl2) - case _ => sys.error("Not matched") - } - assertTypedEquals[Int](3, tmixed._1) - assertTypedEquals[List[Int]](4 :: 5 :: Nil, tmixed._2) - assertTypedEquals[Boolean :: Unit :: HNil](false :: () :: HNil, tmixed._3) - } - - @Test - def testRemove: Unit = { - val l = 1 :: true :: "foo" :: HNil - - val li = l.removeElem[Int] - assertTypedEquals[(Int, Boolean :: String :: HNil)]((1, true :: "foo" :: HNil), li) - - val lb = l.removeElem[Boolean] - assertTypedEquals[(Boolean, Int :: String :: HNil)]((true, 1 :: "foo" :: HNil), lb) - - val ls = l.removeElem[String] - assertTypedEquals[(String, Int :: Boolean :: HNil)](("foo", 1 :: true :: HNil), ls) - - val withDuplicates = 1 :: 'a' :: 'b' :: HNil - val remover = implicitly[Remove.Aux[Int :: Char :: Char :: HNil, Char, (Char, Int :: Char :: HNil)]] - assertTypedEquals[(Char, Int :: Char :: HNil)](('a', 1 :: 'b' :: HNil), remover(withDuplicates)) - } - - @Test - def testRemoveAll: Unit = { - val l = 1 :: true :: "foo" :: HNil - - val lnil = l.removeAll[HNil] - assertTypedEquals[(HNil, Int :: Boolean :: String :: HNil)]((HNil, 1 :: true :: "foo" :: HNil), lnil) - - val li = l.removeAll[Int :: HNil] - assertTypedEquals[(Int :: HNil, Boolean :: String :: HNil)]((1 :: HNil, true :: "foo" :: HNil), li) - - val lb = l.removeAll[Boolean :: HNil] - assertTypedEquals[(Boolean :: HNil, Int :: String :: HNil)]((true :: HNil, 1 :: "foo" :: HNil), lb) - - val lbi = l.removeAll[Boolean :: Int :: HNil] - assertTypedEquals[(Boolean :: Int :: HNil, String :: HNil)]((true :: 1 :: HNil, "foo" :: HNil), lbi) - } - - @Test - def testUnion: Unit = { - type L1 = String :: Long :: HNil - val l1: L1 = "foo" :: 3L :: HNil - - type L2 = Int :: String :: Boolean :: HNil - val l2: L2 = 2 :: "bar" :: true :: HNil - - type L3 = Int :: Int :: HNil - val l3: L3 = 1 :: 2 :: HNil - - type L4 = Int :: Int :: Int :: HNil - val l4: L4 = 4 :: 5 :: 6 :: HNil - - val lnil = l1.union[HNil](HNil) - assertTypedEquals[L1](l1, lnil) - - val lself = l1.union(l1) - assertTypedEquals[L1](l1, lself) - - val l12 = l1.union(l2) - assertTypedEquals[String :: Long :: Int :: Boolean :: HNil]("foo" :: 3L :: 2 :: true :: HNil, l12) - - val l21 = l2.union(l1) - assertTypedEquals[Int :: String :: Boolean :: Long :: HNil](2 :: "bar" :: true :: 3L :: HNil, l21) - - - illTyped { """implicitly[Union.Aux[Int :: HNil, Int :: HNil, Int :: Int :: HNil]]"""} - - val ldup1 = (l3).union(l4) - assertTypedEquals[Int :: Int :: Int :: HNil](1 :: 2 :: 6 :: HNil, ldup1) - - val ldup2 = (l4).union(l3) - assertTypedEquals[Int :: Int :: Int :: HNil](4 :: 5 :: 6 :: HNil, ldup2) - } - - @Test - def testIntersection: Unit = { - type L1 = String :: Long :: Int :: HNil - val l1: L1 = "foo" :: 1L :: 3 :: HNil - - type L2 = Int :: String :: Boolean :: HNil - val l2: L2 = 2 :: "bar" :: true :: HNil - - type L3 = Int :: String :: Int :: HNil - val l3: L3 = 4 :: "foo" :: 5 :: HNil - - val lnil = l1.intersect[HNil] - assertTypedEquals[HNil](HNil, lnil) - - val lself = l1.intersect[L1] - assertTypedEquals[L1](l1, lself) - - val l12 = l1.intersect[L2] - assertTypedEquals[String :: Int :: HNil]("foo" :: 3 :: HNil, l12) - - val l21 = l2.intersect[L1] - assertTypedEquals[Int :: String :: HNil](2 :: "bar" :: HNil, l21) - - illTyped { """implicitly[Intersection.Aux[Int :: HNil, Int :: HNil, HNil]]"""} - - val ldup1 = (l3).intersect[Int :: HNil] - assertTypedEquals[Int :: HNil](4 :: HNil, ldup1) - - val ldup2 = (l3).intersect[Int :: Int :: HNil] - assertTypedEquals[Int :: Int :: HNil](4 :: 5 :: HNil, ldup2) - - val ldup3 = (l3).intersect[String :: HNil] - assertTypedEquals[String :: HNil]("foo" :: HNil, ldup3) - } - - @Test - def testDiff: Unit = { - type L1 = String :: Long :: Int :: HNil - val l1: L1 = "foo" :: 1L :: 3 :: HNil - - type L2 = Int :: String :: Boolean :: HNil - val l2: L2 = 2 :: "bar" :: true :: HNil - - type L3 = Int :: Boolean :: Int :: HNil - val l3: L3 = 4 :: false :: 5 :: HNil - - val lnil = l1.diff[HNil] - assertTypedEquals[L1](l1, lnil) - - val lself = l1.diff[L1] - assertTypedEquals[HNil](HNil, lself) - - val l12 = l1.diff[L2] - assertTypedEquals[Long :: HNil](1L :: HNil, l12) - - val l21 = l2.diff[L1] - assertTypedEquals[Boolean :: HNil](true :: HNil, l21) - - val ldup1 = (l3).diff[Int :: HNil] - assertTypedEquals[Boolean :: Int :: HNil](false :: 5 :: HNil, ldup1) - - val ldup2 = (l3).diff[Int :: Int :: HNil] - assertTypedEquals[Boolean :: HNil](false :: HNil, ldup2) - - val ldup3 = (l3).diff[Boolean :: HNil] - assertTypedEquals[Int :: Int :: HNil](4 :: 5 :: HNil, ldup3) - } - - @Test - def testReinsert: Unit = { - type L = Int :: Boolean :: String :: HNil - - val l: L = 1 :: true :: "foo" :: HNil - - val (i, li) = l.removeElem[Int] - assertTypedEquals[L](li.reinsert[L](i), l) - - val (b, lb) = l.removeElem[Boolean] - assertTypedEquals[L](lb.reinsert[L](b), l) - - val (s, ls) = l.removeElem[String] - assertTypedEquals[L](ls.reinsert[L](s), l) - } - - @Test - def testReinsertAll: Unit = { - type L = Int :: Boolean :: String :: HNil - - val l = 1 :: true :: "foo" :: HNil - - val (nil, lnil) = l.removeAll[HNil] - assertTypedEquals[L](lnil.reinsertAll[L](nil), l) - - val (i, li) = l.removeAll[Int :: HNil] - assertTypedEquals[L](li.reinsertAll[L](i), l) - - val (b, lb) = l.removeAll[Boolean :: HNil] - assertTypedEquals[L](lb.reinsertAll[L](b), l) - - val (bi, lbi) = l.removeAll[Boolean :: Int :: HNil] - assertTypedEquals[L](lbi.reinsertAll[L](bi), l) - } - - object combine extends Poly { - implicit def caseCharString: ProductCase.Aux[Char :: String :: HNil, Int] = use((c : Char, s : String) => s.indexOf(c)) - implicit def caseIntBoolean: ProductCase.Aux[Int :: Boolean :: HNil, String] = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") - } - - object toMapL extends Poly2 { - implicit def wrapMap[T]: Case.Aux[T, Int, Map[List[Int], T]] = - at[T, Int]((end, t) => Map(List(t) -> end)) - } - - @Test - def testFoldLeft: Unit = { - val c1a = combine('o', "foo") - val c1b = combine(c1a, true) - assertTypedEquals[String]("pass", c1b) - - implicitly[LeftFolder.Aux[HNil, String, combine.type, String]] - implicitly[LeftFolder.Aux[Boolean :: HNil, Int, combine.type, String]] - implicitly[LeftFolder.Aux[String :: Boolean :: HNil, Char, combine.type, String]] - - val tf1 = implicitly[LeftFolder[HNil, String, combine.type]] - val tf2 = implicitly[LeftFolder[Boolean :: HNil, Int, combine.type]] - val tf3 = implicitly[LeftFolder[String :: Boolean :: HNil, Char, combine.type]] - - val l1 = "foo" :: true :: HNil - val f1 = l1.foldLeft('o')(combine) - assertTypedEquals[String]("pass", f1) - - val c2a = combine('o', "bar") - val c2b = combine(c2a, false) - assertTypedEquals[String]("pass", c2b) - - val l2 = "bar" :: false :: HNil - val f2 = l2.foldLeft('o')(combine) - assertTypedEquals[String]("pass", f2) - - val l3 = 1 :: 2 :: HNil - val f3 = l3.foldLeft(0)(toMapL) - assertTypedEquals[Map[List[Int], Map[List[Int], Int]]](Map(List(2) -> Map(List(1) -> 0)), f3) - } - - object toMapR extends Poly2 { - implicit def wrapMap[T]: Case.Aux[Int, T, Map[List[Int], T]] = - at[Int, T]((t, end) => Map(List(t) -> end)) - } - - @Test - def testFoldRight: Unit = { - val l1 = 1 :: 2 :: HNil - val f1 = l1.foldRight(0)(toMapR) - assertTypedEquals[Map[List[Int], Map[List[Int], Int]]](Map(List(1) -> Map(List(2) -> 0)), f1) - } - - @Test - def testUpdatedAt: Unit = { - type IBS = Int :: Boolean :: String :: HNil - val l = 1 :: true :: "foo" :: HNil - - val r1 = l.updatedAt[_0](2) - assertTypedEquals[IBS](2 :: true :: "foo" :: HNil, r1) - - val r2 = l.updatedAt[_1](false) - assertTypedEquals[IBS](1 :: false :: "foo" :: HNil, r2) - - val r3 = l.updatedAt[_2]("bar") - assertTypedEquals[IBS](1 :: true :: "bar" :: HNil, r3) - } - - @Test - def testUpdatedAtLiteral: Unit = { - type IBS = Int :: Boolean :: String :: HNil - val l = 1 :: true :: "foo" :: HNil - - val r1 = l.updatedAt(0, 2) - assertTypedEquals[IBS](2 :: true :: "foo" :: HNil, r1) - - val r2 = l.updatedAt(1, false) - assertTypedEquals[IBS](1 :: false :: "foo" :: HNil, r2) - - val r3 = l.updatedAt(2, "bar") - assertTypedEquals[IBS](1 :: true :: "bar" :: HNil, r3) - } - - @Test - def testNatTRel: Unit = { - type L1 = Int :: String :: Boolean :: HNil - type L2 = List[Int] :: List[String] :: List[Boolean] :: HNil - type L3 = Option[Int] :: Option[String] :: Option[Boolean] :: HNil - type L4 = Int :: Int :: Int :: HNil - type L5 = String :: String :: String :: HNil - - implicitly[NatTRel[L1, Id, L2, List]] - implicitly[NatTRel[L2, List, L1, Id]] - - implicitly[NatTRel[L2, List, L3, Option]] - - implicitly[NatTRel[L1, Id, L4, Const[Int]#λ]] - - implicitly[NatTRel[L2, List, L4, Const[Int]#λ]] - } - - object optionToList extends (Option ~> List) { - def apply[A](fa: Option[A]): List[A] = List.fill(3)(fa.toList).flatten - } - - @Test - def testNatTRelMap: Unit = { - type L1 = Option[Int] :: Option[Boolean] :: Option[String] :: Option[Nothing] :: HNil - type L2 = List[Int] :: List[Boolean] :: List[String] :: List[Nothing] :: HNil - val nattrel = implicitly[NatTRel[L1, Option, L2, List]] - - val l1: L1 = Option(1) :: Option(true) :: Option("three") :: None :: HNil - val l2 = nattrel.map(optionToList, l1) - - assertTypedEquals[L2](l2, - List(1, 1, 1) :: List(true, true, true) :: List("three", "three", "three") :: List() :: HNil) - } - - @Test - def testZipConst: Unit = { - type IBS = Int :: Boolean :: String :: HNil - val c = 5 - type WithConst = (Int, Int) :: (Boolean, Int) :: (String, Int) :: HNil - val l = 1 :: true :: "a" :: HNil - typed[IBS](l) - val expected = (1, c) :: (true, c) :: ("a", c) :: HNil - - val zcIntIbs = ZipConst[Int, IBS] - val zipped1 = zcIntIbs(c, l) - assertTypedEquals[WithConst](expected, zipped1) - - val zcaIntIbs = implicitly[ZipConst.Aux[Int, IBS, WithConst]] - assertTypedEquals[WithConst](expected, zcaIntIbs(c, l)) - - val x = l.zipConst(c) - assertTypedEquals[WithConst](expected, x) - - HList().zipConst("") - } - - @Test - def testZipWith: Unit = { - import poly._ - - object empty extends Poly2 - - object add extends Poly2 { - implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) - } - - // HNil zipWith HNil (emptyFn) - val r1 = (HNil: HNil).zipWith(HNil: HNil)(empty) - assertTypedEquals[HNil](HNil, r1) - - // HNil zipWith nonEmpty (emptyFn) - val r2 = (HNil: HNil).zipWith(1 :: HNil)(empty) - assertTypedEquals[HNil](HNil, r2) - - // nonEmpty zipWith HNil (emptyFn) - val r3 = (1 :: HNil).zipWith(HNil: HNil)(empty) - assertTypedEquals[HNil](HNil, r3) - - // singleton zipWith singleton - val r4 = (1 :: HNil).zipWith(2 :: HNil)(add) - assertTypedEquals[Int :: HNil](3 :: HNil, r4) - - { // longList zipWith longerList - type Left = Int :: String :: Double :: HNil - type Right = Int :: Double :: String :: Boolean :: HNil - - val left: Left = 1 :: "foo" :: 1.2 :: HNil - val right: Right = 2 :: 2.3 :: "3.4" :: true :: HNil - - object zipFn extends Poly2 { - implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) - implicit val caseStringDouble: Case.Aux[String, Double, String] = at[String, Double](_ + " -> " + _.toString) - implicit val caseDoubleString: Case.Aux[Double, String, Double] = at[Double, String](_ + _.toDouble) - } - - val r5 = left.zipWith(right)(zipFn) - assertTypedEquals[Int :: String :: Double :: HNil](3 :: "foo -> 2.3" :: 4.6 :: HNil, r5) - } - - def testZipWithIndex: Unit = { - - // HNil zipWithIndex - val r1 = (HNil: HNil).zipWithIndex - assertTypedEquals[HNil](HNil, r1) - - // One element HList zipWithIndex - val r2 = (0::HNil).zipWithIndex - assertTypedEquals[(Int,_0)::HNil]((0,_0)::HNil, r2) - - // HList zipWithIndex - val r3 = (0::1::2::3::HNil).zipWithIndex - assertTypedEquals[(Int,_0)::(Int,_1)::(Int,_2)::(Int,_3)::HNil]((0,_0)::(1,_1)::(2,_2)::(3,_3)::HNil, r3) - - } - - { // invalid polys - illTyped(""" - (1 :: HNil).zipWith(2 :: HNil)(empty) - """) - - object noIntFn extends Poly2 { - implicit val caseDoubleDouble: Case.Aux[Double, Double, Double] = at[Double, Double](_ + _) - } - - illTyped(""" - (1 :: HNil).zipWith(2 :: HNil)(noIntFn) - """) - - illTyped(""" - (1.0 :: 2 :: HNil).zipWith(2.0 :: 3 :: HNil)(noIntFn) - """) - } - } - - @Test - def testWithKeys: Unit = { - import record._ - import syntax.singleton._ - - val orig = - ("intField" ->> 1) :: - ("boolField" ->> true) :: - HNil - - val result = orig.values.zipWithKeys(orig.keys) - sameTyped(orig)(result) - assertEquals(orig, result) - val int = result.get("intField") - assertTypedEquals[Int](1, int) - val bool = result.get("boolField") - assertTypedEquals[Boolean](true, bool) - illTyped("""result.get("otherField")""") - - // key/value lengths must match up - illTyped("orig.tail.values.zipWithKeys(orig.keys)") - illTyped("orig.values.zipWithKeys(orig.keys.tail)") - - // Explicit type argument - { - val result = orig.values.zipWithKeys["intField" :: "boolField" :: HNil] - sameTyped(orig)(result) - assertEquals(orig, result) - val int = result.get("intField") - assertTypedEquals[Int](1, int) - val bool = result.get("boolField") - assertTypedEquals[Boolean](true, bool) - illTyped("""result.get("otherField")""") - - // key/value lengths must match up - illTyped(""" orig.tail.values.zipWithKeys["intField" :: "boolField" :: HNil] """) - illTyped(""" orig.values.zipWithKeys["boolField" :: HNil] """) - } - } - - @Test - def testCollect: Unit = { - import poly._ - - object empty extends Poly1 - - object complex extends Poly1 { - implicit val caseInt: Case.Aux[Int, Double] = at[Int](_.toDouble) - implicit val caseString: Case.Aux[String, Int] = at[String](_ => 1) - } - - val in: Int :: String :: Double :: HNil = 1 :: "foo" :: 2.2 :: HNil - - // HNil collect p - val r1 = (HNil: HNil).collect(empty) - assertTypedEquals[HNil](HNil, r1) - - val r2 = (HNil: HNil).collect(poly.identity) - assertTypedEquals[HNil](HNil, r2) - - val r3 = (HNil: HNil).collect(complex) - assertTypedEquals[HNil](HNil, r3) - - // non-HNil collect empty - val r4 = in.collect(empty) - assertTypedEquals[HNil](HNil, r4) - - // non-HNil collect identity - val r5 = in.collect(identity) - assertTypedEquals[Int :: String :: Double :: HNil](in, r5) - - // non-HNil collect complex - val r6 = in.collect(complex) - assertTypedEquals[Double :: Int :: HNil](1.0 :: 1 :: HNil, r6) - } - - @Test - def testOrdering: Unit = { - assertEquals(List(HNil: HNil, HNil), List(HNil: HNil, HNil).sorted) - - assertEquals(List(1 :: HNil, 2 :: HNil, 3 :: HNil), List(2 :: HNil, 1 :: HNil, 3 :: HNil).sorted) - - assertEquals( - List(1 :: "abc" :: HNil, 1 :: "def" :: HNil, 2 :: "abc" :: HNil, 2 :: "def" :: HNil), - List(2 :: "abc" :: HNil, 1 :: "def" :: HNil, 2 :: "def" :: HNil, 1 :: "abc" :: HNil).sorted - ) - } - - @Test - def testMapCons: Unit = { - type C = Char; type S = String; type I = Int; type D = Double - - val r1 = (HNil: HNil).mapCons('a') - assertTypedEquals[HNil](HNil, r1) - - val r2 = (HNil :: HNil).mapCons('a') - assertTypedEquals[(Char :: HNil) :: HNil]((('a' :: HNil) :: HNil), r2) - - val r3 = ((1 :: HNil) :: ("foo" :: HNil) :: (2.0 :: HNil) :: HNil).mapCons('a') - assertTypedEquals[(C::I::HNil) :: (C::S::HNil) :: (C::D::HNil) :: HNil]( - ('a' :: 1 :: HNil) :: ('a' :: "foo" :: HNil) :: ('a' :: 2.0 :: HNil) :: HNil, - r3 - ) - } - - @Test - def testInterleave: Unit = { - type C = Char; type S = String; type I = Int; type D = Double - def interleave[I, L <: HList](i: I, l: L)(implicit interleave: Interleave[I, L]): interleave.Out = interleave(i, l) - - val r1 = interleave('i', HNil) - assertTypedEquals[(Char :: HNil) :: HNil](('i' :: HNil) :: HNil, r1) - - val r2 = interleave('i', 1 :: HNil) - assertTypedEquals[(C::I::HNil) :: (I::C::HNil) :: HNil](('i' :: 1 :: HNil) :: (1 :: 'i' :: HNil) :: HNil, - r2 - ) - - val r3 = interleave('i', 1 :: "foo" :: HNil) - assertTypedEquals[(C::I::S::HNil) :: (I::C::S::HNil) :: (I::S::C::HNil) :: HNil]( - ('i' :: 1 :: "foo" :: HNil) :: - (1 :: 'i' :: "foo" :: HNil) :: - (1 :: "foo" :: 'i' :: HNil) :: HNil, - r3 - ) - - val r4 = interleave('i', 1 :: "foo" :: 2.0 :: HNil) - assertTypedEquals[(C::I::S::D::HNil) :: (I::C::S::D::HNil) :: (I::S::C::D::HNil) :: (I::S::D::C::HNil) :: HNil]( - ('i' :: 1 :: "foo" :: 2.0 :: HNil) :: - (1 :: 'i' :: "foo" :: 2.0 :: HNil) :: - (1 :: "foo" :: 'i' :: 2.0 :: HNil) :: - (1 :: "foo" :: 2.0 :: 'i' :: HNil) :: HNil, - r4 - ) - } - - @Test - def testFlatMapInterleave: Unit = { - type C = Char; type I = Int - - def flatMapInterleave[I, L <: HList](i: I, l: L)(implicit flatMapInterleave: FlatMapInterleave[I, L]) = - flatMapInterleave(i, l) - - val r1 = flatMapInterleave('i', HNil) - assertTypedEquals[HNil](HNil, r1) - - val r2 = flatMapInterleave('i', HNil :: HNil) - assertTypedEquals[(Char :: HNil) :: HNil](('i' :: HNil) :: HNil, r2) - - val r3 = flatMapInterleave('i', (1 :: HNil) :: (2 :: HNil) :: HNil) - assertTypedEquals[(C::I::HNil) :: (I::C::HNil) :: (C::I::HNil) :: (I::C::HNil) :: HNil]( - ('i' :: 1 :: HNil) :: - (1 :: 'i' :: HNil) :: - ('i' :: 2 :: HNil) :: - (2 :: 'i' :: HNil) :: HNil, - r3 - ) - } - - @Test - def testPermutations: Unit = { - type S = String; type I = Int; type D = Double - - val r1 = HNil.permutations - assertTypedEquals[HNil :: HNil](HNil :: HNil, r1) - - val r2 = (1 :: HNil).permutations - assertTypedEquals[(Int :: HNil) :: HNil]((1 :: HNil) :: HNil, r2) - - val r3 = (1 :: "foo" :: HNil).permutations - assertTypedEquals[(I::S::HNil) :: (S::I::HNil) :: HNil]( - (1 :: "foo" :: HNil) :: - ("foo" :: 1 :: HNil) :: HNil, - r3 - ) - - val r4 = (1 :: "foo" :: 2.0 :: HNil).permutations - assertTypedEquals[ - (I::S::D::HNil) :: (S::I::D::HNil) :: (S::D::I::HNil) :: - (I::D::S::HNil) :: (D::I::S::HNil) :: (D::S::I::HNil) :: HNil - ]( - (1 :: "foo" :: 2.0 :: HNil) :: - ("foo" :: 1 :: 2.0 :: HNil) :: - ("foo" :: 2.0 :: 1 :: HNil) :: - (1 :: 2.0 :: "foo" :: HNil) :: - (2.0 :: 1 :: "foo" :: HNil) :: - (2.0 :: "foo" :: 1 :: HNil) :: HNil, - r4 - ) - } - - @Test - def testMkString: Unit = { - assertEquals(s"⸨1, foo, ${2.0}⸩", (1 :: "foo" :: 2.0 :: HNil).mkString("⸨", ", ", "⸩")) - } - - @Test - def testRotateLeft: Unit = { - val in0 = HNil - val in1 = 1 :: HNil - val in2 = 1 :: "foo" :: HNil - val in3 = 1 :: "foo" :: 2.0 :: HNil - val in4 = 1 :: "foo" :: 2.0 :: 'a' :: HNil - type S = String; type I = Int; type D = Double; type C = Char - - { // rotateLeft(0) - val r1 = in0.rotateLeft(0) - assertTypedSame[HNil](HNil, r1) - val r2 = in1.rotateLeft(0) - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateLeft(0) - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in3.rotateLeft(0) - assertTypedSame[I :: S :: D :: HNil](in3, r4) - val r5 = in4.rotateLeft(0) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) - } - - { // rotateLeft[_0] - val r1 = in0.rotateLeft[_0] - assertTypedSame[HNil](HNil, r1) - val r2 = in1.rotateLeft[_0] - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateLeft[_0] - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in3.rotateLeft[_0] - assertTypedSame[I :: S :: D :: HNil](in3, r4) - val r5 = in4.rotateLeft[_0] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) - } - - { // rotateLeft(n % size == 0) - val r1 = in1.rotateLeft(1) - assertTypedSame[I :: HNil](in1, r1) - val r2 = in1.rotateLeft(2) - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateLeft(2) - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in2.rotateLeft(4) - assertTypedSame[I :: S :: HNil](in2, r4) - val r5 = in3.rotateLeft(3) - assertTypedSame[I :: S :: D :: HNil](in3, r5) - val r6 = in3.rotateLeft(6) - assertTypedSame[I :: S :: D :: HNil](in3, r6) - val r7 = in4.rotateLeft(4) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) - val r8 = in4.rotateLeft(8) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) - } - - { // rotateLeft[N % Size == 0] - val r1 = in1.rotateLeft[_1] - assertTypedSame[I :: HNil](in1, r1) - val r2 = in1.rotateLeft[_2] - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateLeft[_2] - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in2.rotateLeft[_4] - assertTypedSame[I :: S :: HNil](in2, r4) - val r5 = in3.rotateLeft[_3] - assertTypedSame[I :: S :: D :: HNil](in3, r5) - val r6 = in3.rotateLeft[_6] - assertTypedSame[I :: S :: D :: HNil](in3, r6) - val r7 = in4.rotateLeft[_4] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) - val r8 = in4.rotateLeft[_8] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) - } - - { // other(n) - val r1 = in2.rotateLeft(1) - assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) - - val r2 = in3.rotateLeft(1) - assertTypedEquals[S :: D :: I :: HNil]("foo" :: 2.0 :: 1 :: HNil, r2) - - val r3 = in4.rotateLeft(1) - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r3) - - val r4 = in4.rotateLeft(2) - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) - - val r5 = in4.rotateLeft(3) - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r5) - - val r6 = in4.rotateLeft(5) - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r6) - - val r7 = in4.rotateLeft(6) - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) - } - - { // other[N] - val r1 = in2.rotateLeft[_1] - assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) - - val r2 = in3.rotateLeft[_1] - assertTypedEquals[S :: D :: I :: HNil]("foo" :: 2.0 :: 1 :: HNil, r2) - - val r3 = in4.rotateLeft[_1] - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r3) - - val r4 = in4.rotateLeft[_2] - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) - - val r5 = in4.rotateLeft[_3] - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r5) - - val r6 = in4.rotateLeft[_5] - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r6) - - val r7 = in4.rotateLeft[_6] - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) - } - } - - @Test - def testRotateRight: Unit = { - val in0 = HNil - val in1 = 1 :: HNil - val in2 = 1 :: "foo" :: HNil - val in3 = 1 :: "foo" :: 2.0 :: HNil - val in4 = 1 :: "foo" :: 2.0 :: 'a' :: HNil - type S = String; type I = Int; type D = Double; type C = Char - - { // rotateRight(0) - val r1 = in0.rotateRight(0) - assertTypedSame[HNil](HNil, r1) - val r2 = in1.rotateRight(0) - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateRight(0) - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in3.rotateRight(0) - assertTypedSame[I :: S :: D :: HNil](in3, r4) - val r5 = in4.rotateRight(0) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) - } - - { // rotateRight[_0] - val r1 = in0.rotateRight[_0] - assertTypedSame[HNil](HNil, r1) - val r2 = in1.rotateRight[_0] - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateRight[_0] - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in3.rotateRight[_0] - assertTypedSame[I :: S :: D :: HNil](in3, r4) - val r5 = in4.rotateRight[_0] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) - } - - { // rotateRight(n % size == 0) - val r1 = in1.rotateRight(1) - assertTypedSame[I :: HNil](in1, r1) - val r2 = in1.rotateRight(2) - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateRight(2) - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in2.rotateRight(4) - assertTypedSame[I :: S :: HNil](in2, r4) - val r5 = in3.rotateRight(3) - assertTypedSame[I :: S :: D :: HNil](in3, r5) - val r6 = in3.rotateRight(6) - assertTypedSame[I :: S :: D :: HNil](in3, r6) - val r7 = in4.rotateRight(4) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) - val r8 = in4.rotateRight(8) - assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) - } - - { // rotateRight[N % Size == 0] - val r1 = in1.rotateRight[_1] - assertTypedSame[I :: HNil](in1, r1) - val r2 = in1.rotateRight[_2] - assertTypedSame[I :: HNil](in1, r2) - val r3 = in2.rotateRight[_2] - assertTypedSame[I :: S :: HNil](in2, r3) - val r4 = in2.rotateRight[_4] - assertTypedSame[I :: S :: HNil](in2, r4) - val r5 = in3.rotateRight[_3] - assertTypedSame[I :: S :: D :: HNil](in3, r5) - val r6 = in3.rotateRight[_6] - assertTypedSame[I :: S :: D :: HNil](in3, r6) - val r7 = in4.rotateRight[_4] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) - val r8 = in4.rotateRight[_8] - assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) - } - - { // others(n) - val r1 = in2.rotateRight(1) - assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) - - val r2 = in3.rotateRight(1) - assertTypedEquals[D :: I :: S :: HNil](2.0 :: 1 :: "foo" :: HNil, r2) - - val r3 = in4.rotateRight(1) - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r3) - - val r4 = in4.rotateRight(2) - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) - - val r5 = in4.rotateRight(3) - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r5) - - val r6 = in4.rotateRight(5) - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r6) - - val r7 = in4.rotateRight(6) - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) - } - - { // others[N] - val r1 = in2.rotateRight[_1] - assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) - - val r2 = in3.rotateRight[_1] - assertTypedEquals[D :: I :: S :: HNil](2.0 :: 1 :: "foo" :: HNil, r2) - - val r3 = in4.rotateRight[_1] - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r3) - - val r4 = in4.rotateRight[_2] - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) - - val r5 = in4.rotateRight[_3] - assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r5) - - val r6 = in4.rotateRight[_5] - assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r6) - - val r7 = in4.rotateRight[_6] - assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) - } - } - - object smear extends Poly { - implicit val caseIntInt: ProductCase.Aux[Int :: Int :: HNil, Int] = use((x: Int, y: Int) => x + y) - implicit val caseStringInt: ProductCase.Aux[String :: Int :: HNil, Int] = use((x: String, y: Int) => x.toInt + y) - implicit val caseIntString: ProductCase.Aux[Int :: String :: HNil, Int] = use((x: Int, y: String) => x + y.toInt) - } - - @Test - def testScanLeft: Unit = { - val in = 1 :: "2" :: HNil - val out = in.scanLeft(1)(smear) - - typed[Int :: Int :: Int :: HNil](out) - assertEquals(1 :: 2 :: 4 :: HNil, out) - } - - @Test - def testScanRight: Unit = { - val in = 1 :: "2" :: HNil - val out = in.scanRight(1)(smear) - - typed[Int :: Int :: Int :: HNil](out) - assertEquals(4 :: 3 :: 1 :: HNil, out) - } - - @Test - def testFill: Unit = { - { - val empty = HList.fill(0)(true) - typed[_0](empty.length) - } - - { - val empty = HList.fill[Boolean](0)(true) - typed[_0](empty.length) - } - - { - val single = HList.fill(1)(None) - typed[_1](single.length) - typed[None.type](single.head) - assertEquals(None, single.head) - } - - { - val single = HList.fill[None.type](1)(None) - typed[_1](single.length) - typed[None.type](single.head) - assertEquals(None, single.head) - } - - { - val three = HList.fill(3)(m2i) - typed[_3](three.length) - typed[M2[Int, Unit]](three(_0)) - typed[M2[Int, Unit]](three(_1)) - typed[M2[Int, Unit]](three(_2)) - assertEquals(m2i, three(_0)) - assertEquals(m2i, three(_1)) - assertEquals(m2i, three(_2)) - } - - { - val three = HList.fill[M2[Int, Unit]](3)(m2i) - typed[_3](three.length) - typed[M2[Int, Unit]](three(_0)) - typed[M2[Int, Unit]](three(_1)) - typed[M2[Int, Unit]](three(_2)) - assertEquals(m2i, three(_0)) - assertEquals(m2i, three(_1)) - assertEquals(m2i, three(_2)) - } - - { - val empty = HList.fill(0, 0)(true) - typed[_0](empty.length) - } - - { - val empty = HList.fill[Boolean](0, 0)(true) - typed[_0](empty.length) - } - - { - val empty = HList.fill(2, 0)(true) - typed[_2](empty.length) - typed[_0](empty(_0).length) - typed[_0](empty(_1).length) - } - - { - val empty = HList.fill[Boolean](2, 0)(true) - typed[_2](empty.length) - typed[_0](empty(_0).length) - typed[_0](empty(_1).length) - } - - { - val empty = HList.fill(0, 2)(true) - typed[_0](empty.length) - } - - { - val empty = HList.fill[Boolean](0, 2)(true) - typed[_0](empty.length) - } - - { - val oneByTwo = HList.fill(1, 2)(None) - typed[_1](oneByTwo.length) - typed[_2](oneByTwo.head.length) - typed[None.type](oneByTwo.head(_0)) - typed[None.type](oneByTwo.head(_1)) - assertEquals(None, oneByTwo.head(_0)) - assertEquals(None, oneByTwo.head(_1)) - } - - { - val oneByTwo = HList.fill[None.type](1, 2)(None) - typed[_1](oneByTwo.length) - typed[_2](oneByTwo.head.length) - typed[None.type](oneByTwo.head(_0)) - typed[None.type](oneByTwo.head(_1)) - assertEquals(None, oneByTwo.head(_0)) - assertEquals(None, oneByTwo.head(_1)) - } - - { - val twoByThree = HList.fill(2, 3)(None) - typed[_2](twoByThree.length) - typed[_3](twoByThree(_0).length) - typed[_3](twoByThree(_1).length) - typed[None.type](twoByThree.at[_0].at[_0]) - typed[None.type](twoByThree.at[_0].at[_1]) - typed[None.type](twoByThree.at[_0].at[_2]) - typed[None.type](twoByThree.at[_1].at[_0]) - typed[None.type](twoByThree.at[_1].at[_1]) - typed[None.type](twoByThree.at[_1].at[_2]) - assertEquals(None, twoByThree.at[_0].at[_0]) - assertEquals(None, twoByThree.at[_0].at[_1]) - assertEquals(None, twoByThree.at[_0].at[_2]) - assertEquals(None, twoByThree.at[_1].at[_0]) - assertEquals(None, twoByThree.at[_1].at[_1]) - assertEquals(None, twoByThree.at[_1].at[_2]) - } - - { - val twoByThree = HList.fill[None.type](2, 3)(None) - typed[_2](twoByThree.length) - typed[_3](twoByThree(_0).length) - typed[_3](twoByThree(_1).length) - typed[None.type](twoByThree.at[_0].at[_0]) - typed[None.type](twoByThree.at[_0].at[_1]) - typed[None.type](twoByThree.at[_0].at[_2]) - typed[None.type](twoByThree.at[_1].at[_0]) - typed[None.type](twoByThree.at[_1].at[_1]) - typed[None.type](twoByThree.at[_1].at[_2]) - assertEquals(None, twoByThree.at[_0].at[_0]) - assertEquals(None, twoByThree.at[_0].at[_1]) - assertEquals(None, twoByThree.at[_0].at[_2]) - assertEquals(None, twoByThree.at[_1].at[_0]) - assertEquals(None, twoByThree.at[_1].at[_1]) - assertEquals(None, twoByThree.at[_1].at[_2]) - } - } - - @Test - def testPolyFill = { - object zero extends Poly0 { - implicit val zeroInt: Case0[Int] = at[Int](0) - } - - implicit val emptyString: zero.Case0[String] = zero.at[String]("") - - val out = HList.fillWith[Int :: String :: Int :: HNil](zero) - assertEquals(out, 0 :: "" :: 0 :: HNil) - } - - @Test - def testPatch: Unit = { - val basehl = 1 :: 2 :: "three" :: HNil - - { //patch an empty hlist - val out = HNil.patch(0, basehl, 0) - val out2 = HNil.patch[_0,_0](basehl) - - typed[Int :: Int :: String :: HNil](out) - assertEquals(out, basehl) - assertTypedEquals[Int :: Int :: String :: HNil](out, out2) - } - - { //single patch w/ nothing removed - val out = basehl.patch(1, 4 :: HNil, 0) - val out2 = basehl.patch[_1,_0](4 :: HNil) - - typed[Int :: Int :: Int :: String :: HNil](out) - assertEquals(1 :: 4 :: 2 :: "three" :: HNil, out) - assertTypedEquals[Int :: Int :: Int :: String :: HNil](out, out2) - } - - { //single patch w/ 2 elements removed - val out = basehl.patch(1, 3 :: HNil, 2) - val out2 = basehl.patch[_1,_2](3 :: HNil) - - typed[Int :: Int :: HNil](out) - assertEquals(1 :: 3 :: HNil, out) - assertTypedEquals[Int :: Int :: HNil](out, out2) - } - - { //essentially append - val p = 4 :: 5 :: "six" :: HNil - val out = basehl.patch(3, p, 0) - val out2 = basehl.patch[_3,_0](p) - - typed[Int :: Int :: String :: Int :: Int :: String :: HNil](out) - assertEquals(1 :: 2 :: "three" :: 4 :: 5 :: "six" :: HNil, out) - assertTypedEquals[Int :: Int :: String :: Int :: Int :: String :: HNil](out, out2) - } - - { //several patched w/ everything from original removed - val sub = 4 :: "five" :: "six" :: HNil - val out = basehl.patch(0, sub, 3) - val out2 = basehl.patch[_0,_3](sub) - - typed[Int :: String :: String :: HNil](out) - assertEquals(sub, out) - assertTypedEquals[Int :: String :: String :: HNil](out, out2) - } - } - - @Test - def testToCoproduct: Unit = { - type PISB = Int :: String :: Boolean :: HNil - type CISBa = Int :+: String :+: Boolean :+: CNil - val toCoproduct = ToCoproduct[PISB] - type CISBb = toCoproduct.Out - implicitly[CISBa =:= CISBb] - } - - @Test - def testToSum: Unit = { - type PISB = Int :: String :: Boolean :: HNil - type CISBa = Int :+: String :+: Boolean :+: CNil - val toSum1 = ToSum[PISB] - type SISBa = toSum1.Out - implicitly[CISBa =:= SISBa] - - type PIISSB = Int :: Int :: String :: String :: Boolean :: HNil - val toSum2 = ToSum[PIISSB] - type SISBb = toSum2.Out - implicitly[CISBa =:= SISBb] - } - - @Test - def testHListTypeSelector: Unit = { - import syntax.singleton._ - - typed[HNil](HNil) - - typed[Int :: HNil](23 :: HNil) - - typed[Int :: String :: HNil](23 :: "foo" :: HNil) - - typed[Int :: String :: Boolean :: HNil](23 :: "foo" :: true :: HNil) - - // Literal types - - typed[2 :: HNil](2.narrow :: HNil) - - typed[2 :: "a" :: true :: HNil](2.narrow :: "a".narrow :: true.narrow :: HNil) - - illTyped(""" typed[2 :: HNil](3.narrow :: HNil) """) - - // Mix of standard and literal types - - typed[2 :: String :: true :: HNil](2.narrow :: "a" :: true.narrow :: HNil) - } - - @Test - def selectAllTest: Unit ={ - import shapeless._, record._ , ops.hlist.SelectAll - - //is there any way to do it without runtime overhead? - class TypeCaptured[T](val value: T) { - type _type = T - } - - def getFieldsByTypesOfSuper[Sub <: HList, Super <: HList](l: Sub)(implicit sa: SelectAll[Sub, Super]) = sa(l) - - val hsuper = new TypeCaptured("2":: true :: HNil) - val hsub = new TypeCaptured(1 :: "2":: true :: HNil) - - //testing with plain HList - assertTypedEquals[hsuper._type](hsuper.value, getFieldsByTypesOfSuper[hsub._type, hsuper._type](hsub.value)) - - val rsuper = new TypeCaptured(Record(b = true, c = "blah")) - val rsub = new TypeCaptured(Record(a = 1, b = true, c = "blah")) - - //testing with Record - assertTypedEquals[rsuper._type](rsuper.value, getFieldsByTypesOfSuper[rsub._type, rsuper._type](rsub.value)) - - } - - @Test - def testCollectFirst: Unit = { - object Foo extends Poly1{ - implicit def iinst: Case.Aux[Int, Int] = at[Int]{ _ + 1 } - } - val hlist1 = "foo" :: 2.0 :: 1 :: HNil - assertTypedEquals[Int](hlist1.collectFirst(Foo), 2) - - val hlist2 = "foo" :: 2.0 :: HNil - illTyped("""hlist2.collectFirst(Foo)""") - } - - @Test - def testGrouper: Unit = { - object toInt extends Poly1 { - implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) - } - def range[R <: HList](a: Nat, b: Nat)(implicit - range: ops.nat.Range.Aux[a.N, b.N, R], - mapper: ops.hlist.Mapper[toInt.type, R] - ) = mapper(range()) - - // group HNil - assertEquals(HNil: HNil, (HNil: HNil).group(2, 1)) - // group a HList of 4 items into 2 (4/2) tuples of 2 items - assertEquals( - (0, 1) ::(2, 3) :: HNil, - range(0, 4).group(2, 2) - ) - - // group a HList of 5 items into 2 (5/2) tuples of 2 items - // the last item does not make a complete partition and is dropped. - assertEquals( - (0, 1) ::(2, 3) :: HNil, - range(0, 5).group(2, 2) - ) - - // uses the step to select the starting point for each partition - assertEquals( - (0, 1) ::(4, 5) :: HNil, - range(0, 6).group(2, 4) - ) - - // if the step is smaller than the partition size, items will be reused - assertEquals( - (0, 1) ::(1, 2) ::(2, 3) :: HNil, - range(0, 4).group(2, 1) - ) - - // when there are not enough items to fill the last partition, a pad can be supplied. - assertEquals( - (0, 1) ::(2, 3) ::(4, 'a') :: HNil, - range(0, 5).group(2, 2, 'a' :: HNil) - ) - - // but only as many pad elements are used as necessary to fill the final partition. - assertEquals( - (0, 1) ::(2, 3) ::(4, 'a') :: HNil, - range(0, 5).group(2, 2, 'a' :: 'b' :: 'c' :: HNil) - ) - - } - - @Test - def testLiftAll: Unit = { - trait F[A] - implicit object FInt extends F[Int] - implicit object FString extends F[String] - - assertEquals(HNil, implicitly[LiftAll[F, HNil]].instances) - assertEquals(FInt :: HNil, implicitly[LiftAll[F, Int :: HNil]].instances) - assertEquals(FString :: FInt :: HNil, implicitly[LiftAll[F, String :: Int :: HNil]].instances) - illTyped("implicitly[LiftAll[F, Long :: String :: Int :: HNil]]") - - assertEquals(FInt :: HNil, LiftAll[F](1 :: HNil).instances) - } - - @Test - def testPadTo: Unit = { - val p1 = (1 :: "a" :: HNil).padTo(3, 0) - assertTypedEquals[Int :: String :: Int :: HNil](1 :: "a" :: 0 :: HNil, p1) - - val p2 = (1 :: "a" :: HNil).padTo(2, 0) - assertTypedEquals[Int :: String :: HNil](1 :: "a" :: HNil, p2) - - val p3 = (HNil: HNil).padTo(2, "a") - assertTypedEquals[String :: String :: HNil]("a" :: "a" :: HNil, p3) - - val p4 = (HNil: HNil).padTo(0, "a") - assertTypedEquals[HNil](HNil, p4) - - illTyped(""" (1 :: "a" :: HNil).padTo(1, 0) """) - } - - @Test - def testSlice: Unit = { - val r1 = (1 :: "a" :: 3 :: HNil).slice(0, 2) - assertTypedEquals[Int :: String :: HNil](1 :: "a" :: HNil, r1) - - val r2 = (1 :: "a" :: 3 :: HNil).slice(1, 2) - assertTypedEquals[String :: HNil]("a" :: HNil, r2) - - val r3 = (1 :: "a" :: 3 :: HNil).slice(2, 3) - assertTypedEquals[Int :: HNil](3 :: HNil, r3) - - val r4 = (HNil: HNil).slice(0, 0) - assertTypedEquals[HNil](HNil, r4) - - illTyped(""" (1 :: "a" :: 3 :: HNil).slice(0, 4) """) - illTyped(""" (1 :: "a" :: 3 :: HNil).slice(1, 0) """) - } - - @Test - def testToSizedHList: Unit = { - val ns = List(1,2,3,4) - assertTypedEquals[Option[III]](None, ns.toSizedHList(3)) - assertTypedEquals[Option[IIII]](Some(1 :: 2 :: 3 :: 4 :: HNil), ns.toSizedHList(4)) - } - - @Test - def testModifierAt: Unit = { - // first element - assertEquals((1, 42 :: 2 :: 3 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(0)(_ => 42)) - - //last element - assertEquals((3, 1 :: 2 :: 42 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(2)(_ => 42)) - - //different type - assertEquals((3, 1 :: 2 :: 42.0 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(2)(_ => 42.0)) - } - - @Test - def testReify: Unit = { - import syntax.singleton._ - - assertTypedEquals(HNil, Reify[HNil].apply()) - - assertTypedEquals("a".narrow :: HNil, Reify["a" :: HNil].apply()) - - assertTypedEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify["a" :: 1 :: "b" :: true :: HNil].apply()) - - illTyped("Reify[String :: Int :: HNil]") - illTyped("""Reify[String :: ("a" :: 1 :: "b" :: true :: HNil)]""") - } - - @Test - def testCombinations: Unit = { - type I = Int; type S = String - - val r1 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(2) - assertTypedEquals[ - (I :: S :: HNil) :: - (I :: I :: HNil) :: - (I :: I :: HNil) :: - (S :: I :: HNil) :: - (S :: I :: HNil) :: - (I :: I :: HNil) :: HNil - ]( - (1 :: "2" :: HNil) :: - (1 :: 3 :: HNil) :: - (1 :: 4 :: HNil) :: - ("2" :: 3 :: HNil) :: - ("2" :: 4 :: HNil) :: - (3 :: 4 :: HNil) :: HNil, r1) - - val r2 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(3) - assertTypedEquals[ - (I :: S :: I :: HNil) :: - (I :: S :: I :: HNil) :: - (I :: I :: I :: HNil) :: - (S :: I :: I :: HNil) :: HNil - ]( - (1 :: "2" :: 3 :: HNil) :: - (1 :: "2" :: 4 :: HNil) :: - (1 :: 3 :: 4 :: HNil) :: - ("2" :: 3 :: 4 :: HNil) :: HNil, r2) - - val r3 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(4) - assertTypedEquals[ - (I :: S :: I :: I :: HNil) :: HNil - ]( - (1 :: "2" :: 3 :: 4 :: HNil) :: HNil, r3) - - val r4 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(5) - assertTypedEquals[HNil](HNil, r4) - - val r5 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(0) - assertTypedEquals[HNil :: HNil](HNil :: HNil, r5) - } - - @Test - def testIsHCons = assertTypedEquals[Int :: HNil](23 :: HNil, IsHCons[Int :: HNil].cons(23, HNil)) - - @Test - def testToProduct = { - val isbd = 2 :: "abc" :: true :: 3.0 :: HNil - val p = (2, ("abc", (true, (3.0, ())))) - - import syntax.std.tuple._ - assertEquals(isbd.toProduct, p) - assertEquals(p.toHList, isbd) - assertEquals(isbd.toProduct.toHList, isbd) - assertEquals(p.toHList.toProduct, p) - assertEquals((), (HNil: HNil).toProduct) - assertEquals(HNil, ().toHList) - } - - @Test - def testAuxImplicits: Unit = { - the[SplitRight.Aux[String :: Int :: Boolean :: HNil, Int, String :: Int :: HNil, Boolean :: HNil]] - the[Grouper.Aux[Int :: String :: Boolean :: HNil, _2, _1, (Int, String) :: (String, Boolean) :: HNil]] - the[PaddedGrouper.Aux[Int :: String :: Boolean :: HNil, _2, _2, Long :: HNil, (Int, String) :: (Boolean, Long) :: HNil]] - } -} +/* + * Copyright (c) 2011-14 Miles Sabin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package shapeless + +import org.junit.Test +import org.junit.Assert._ + +import test._ +import testutil._ + +class HListTests extends HListTestsScalaCompat { + import nat._ + import poly._ + import syntax.std.traversable._ + import syntax.singleton._ + import syntax.typeable._ + import ops.hlist._ + import ops.record.SelectAll + + type SI = Set[Int] :: HNil + type OI = Option[Int] :: HNil + + type III = Int :: Int :: Int :: HNil + + type SISS = Set[Int] :: Set[String] :: HNil + type OIOS = Option[Int] :: Option[String] :: HNil + + type ISII = Int :: String :: Int :: Int :: HNil + type IIII = Int :: Int :: Int :: Int :: HNil + type IYII = Int :: Any :: Int :: Int :: HNil + + type OIOSOIOI = Option[Int] :: Option[String] :: Option[Int] :: Option[Int] :: HNil + type SISSSISI = Set[Int] :: Set[String] :: Set[Int] :: Set[Int] :: HNil + + type BBBB = Boolean :: Boolean :: Boolean :: Boolean :: HNil + + object mkString extends (Any -> String)(_.toString) + object fruit extends (Fruit -> Fruit)(f => f) + object incInt extends (Int >-> Int)(_ + 1) + object extendedChoose extends LiftU(choose) + + trait Fruit + case class Apple() extends Fruit + case class Pear() extends Fruit + case class Banana() extends Fruit + + type YYYY = Any :: Any :: Any :: Any :: HNil + type FF = Fruit :: Fruit :: HNil + type AP = Apple :: Pear :: HNil + type BP = Banana :: Pear :: HNil + type AF = Apple :: Fruit :: HNil + type FFFF = Fruit :: Fruit :: Fruit :: Fruit :: HNil + type APAP = Apple :: Pear :: Apple :: Pear :: HNil + type APBP = Apple :: Pear :: Banana :: Pear :: HNil + type APB = Apple :: Pear :: Banana :: HNil + type PBPA = Pear :: Banana :: Pear :: Apple :: HNil + type PABP = Pear :: Apple :: Banana :: Pear :: HNil + + type APc = Apple :+: Pear :+: CNil + type ABPc = Apple :+: Banana :+: Pear :+: CNil + + val a : Apple = Apple() + val p : Pear = Pear() + val b : Banana = Banana() + val f : Fruit = new Fruit {} + + val ap : AP = a :: p :: HNil + val bp : BP = b :: p :: HNil + val apap : APAP = a :: p :: a :: p :: HNil + val apbp : APBP = a :: p :: b :: p :: HNil + val apapList = a :: p :: a :: p :: Nil + val apbpList = a :: p :: b :: p :: Nil + val apapArray = Array(a, p, a, p) + val apbpArray = Array(a, p, b, p) + + trait Ctv[-T] + type CICSCICICD = Ctv[Int] :: Ctv[String] :: Ctv[Int] :: Ctv[Int] :: Ctv[Double] :: HNil + + val ci: Ctv[Int] = new Ctv[Int] {} + val cs: Ctv[String] = new Ctv[String] {} + val cd: Ctv[Double] = new Ctv[Double] {} + val cicscicicdList = ci :: cs :: ci :: ci :: cd :: Nil + val cicscicicdArray = Array(ci, cs, ci, ci, cd) + val cicscicicd: CICSCICICD = ci :: cs :: ci :: ci :: cd :: HNil + + trait M[T] + type MIMSMIMIMD = M[Int] :: M[String] :: M[Int] :: M[Int] :: M[Double] :: HNil + + val mi: M[Int] = new M[Int] {} + val ms: M[String] = new M[String] {} + val md: M[Double] = new M[Double] {} + val mimsmimimdList = mi :: ms :: mi :: mi :: md :: Nil + val mimsmimimdArray = Array(mi, ms, mi, mi, md) + val mimsmimimd: MIMSMIMIMD = mi :: ms :: mi :: mi :: md :: HNil + + import language.existentials + val mExist: M[_] = new M[Double] {} + type MIMSMIMEMD = M[Int] :: M[String] :: M[Int] :: M[_] :: M[Double] :: HNil + val mimsmimemdList = mi :: ms :: mi :: mExist :: md :: Nil + val mimsmimemdArray = Array[M[_]](mi, ms, mi, mExist, md) + val mimsmimemd: MIMSMIMEMD = mi :: ms :: mi :: mExist :: md :: HNil + + trait M2[A,B] + type M2IM2SM2IM2IM2D = M2[Int, Unit] :: M2[String, Unit] :: M2[Int, Unit] :: M2[Int, Unit] :: M2[Double, Unit] :: HNil + + val m2i: M2[Int, Unit] = new M2[Int, Unit] {} + val m2s: M2[String, Unit] = new M2[String, Unit] {} + val m2d: M2[Double, Unit] = new M2[Double, Unit] {} + val m2im2sm2im2im2dList = m2i :: m2s :: m2i :: m2i :: m2d :: Nil + val m2im2sm2im2im2dArray = Array(m2i, m2s, m2i, m2i, m2d) + val m2im2sm2im2im2d: M2IM2SM2IM2IM2D = m2i :: m2s :: m2i :: m2i :: m2d :: HNil + + val m2iExist: M2[Int, _] = new M2[Int, Unit] {} + val m2sExist: M2[String, _] = new M2[String, Unit] {} + val m2dExist: M2[Double, _] = new M2[Double, Unit] {} + type M2EIM2ESM2EIM2EEM2ED = M2[Int, _] :: M2[String, _] :: M2[Int, _] :: M2[Int, _] :: M2[Double, _] :: HNil + val m2eim2esm2eim2eem2edList = m2iExist :: m2sExist :: m2iExist :: m2iExist :: m2dExist :: Nil + val m2eim2esm2eim2eem2edArray = Array(m2iExist, m2sExist, m2iExist, m2iExist, m2dExist) + val m2eim2esm2eim2eem2ed: M2EIM2ESM2EIM2EEM2ED = m2iExist :: m2sExist :: m2iExist :: m2iExist :: m2dExist :: HNil + + + @Test + def testBasics: Unit = { + val l = 1 :: "foo" :: 2.0 :: HNil + + val r1 = l.head + assertTypedEquals[Int](1, r1) + + val r2 = l.tail.head + assertTypedEquals[String]("foo", r2) + + assertEquals(2.0, l.tail.tail.head, Double.MinPositiveValue) + + illTyped(""" + HNil.head + """) + + illTyped(""" + HNil.tail + """) + + illTyped(""" + l.tail.tail.tail.head + """) + } + + @Test + def testMap: Unit = { + implicitly[Mapper.Aux[choose.type, HNil, HNil]] + implicitly[choose.Case[Set[Int]]] + implicitly[Mapper.Aux[choose.type, Set[Int] :: HNil, Option[Int] :: HNil]] + + val s1 = Set(1) :: HNil + val o1 = s1 map choose + assertTypedEquals[OI](Option(1) :: HNil, o1) + + val s2 = Set(1) :: Set("foo") :: HNil + val o2 = s2 map choose + assertTypedEquals[OIOS](Option(1) :: Option("foo") :: HNil, o2) + + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + + val l2 = l1 map singleton + assertTypedEquals[SISSSISI](Set(1) :: Set("foo") :: Set(2) :: Set(3) :: HNil, l2) + + val l3 = l1 map option + assertTypedEquals[OIOSOIOI](Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil, l3) + + val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + + val l5 = l4 map get + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, l5) + + typed[Int](l5.head) + typed[String](l5.tail.head) + typed[Int](l5.tail.tail.head) + typed[Int](l5.tail.tail.tail.head) + + val l6 = l1 map identity + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, l6) + + val l7 = l4 map isDefined + assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) + + val l8 = 23 :: "foo" :: true :: HNil + val l9 = l8 map mkString + assertTypedEquals[String :: String :: String :: HNil]("23" :: "foo" :: "true" :: HNil, l9) + + val l10 = apbp map fruit + assertTypedEquals[Fruit :: Fruit :: Fruit :: Fruit :: HNil](apbp, l10) + + val l11 = apbp map mkString + assertTypedEquals[String :: String :: String :: String :: HNil]("Apple()" :: "Pear()" :: "Banana()" :: "Pear()" :: HNil, l11) + } + + @Test + def testMapped: Unit = { + implicitly[Mapped.Aux[HNil, Option, HNil]] + implicitly[Mapped.Aux[Int :: String :: HNil, Option, Option[Int] :: Option[String] :: HNil]] + + implicitly[Mapped.Aux[HNil, Id, HNil]] + implicitly[Mapped.Aux[Int :: String :: HNil, Id, Int :: String :: HNil]] + + implicitly[Mapped.Aux[HNil, Const[Int]#λ, HNil]] + implicitly[Mapped.Aux[Double :: String :: HNil, Const[Int]#λ, Int :: Int :: HNil]] + } + + object dup extends Poly1 { + implicit def default[T]: Case.Aux[T, T :: T :: HNil] = at[T](t => t :: t :: HNil) + } + + @Test + def testFlatMap: Unit = { + val l1 = 1 :: "foo" :: true :: HNil + + val l2 = l1 flatMap dup + assertTypedEquals[Int :: Int :: String :: String :: Boolean :: Boolean :: HNil]( + 1 :: 1 :: "foo" :: "foo" :: true :: true :: HNil, l2) + + val l3 = (1 :: "foo" :: HNil) :: (HNil : HNil) :: (2.0 :: true :: HNil) :: ("bar" :: HNil) :: HNil + + val l4 = l3 flatMap identity + assertTypedEquals[Int :: String :: Double :: Boolean :: String :: HNil]( + 1 :: "foo" :: 2.0 :: true :: "bar" :: HNil, l4) + + val l5 = 23 :: "foo" :: 7 :: true :: 0 :: HNil + val l6 = l5 flatMap incInt + assertTypedEquals[Int :: Int :: Int :: HNil](24 :: 8 :: 1 :: HNil, l6) + + val l7 = Set(23) :: "foo" :: Set(true) :: 23 :: HNil + val l8 = l7 flatMap extendedChoose + assertTypedEquals[Option[Int] :: Option[Boolean] :: HNil](Option(23) :: Option(true) :: HNil, l8) + } + + @Test + def testConformance: Unit = { + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + assertTypedEquals[Any :: AnyRef :: Any :: Any :: HNil](1 :: "foo" :: 2 :: 3 :: HNil, l1) + + val ap = a :: p :: HNil + typed[AP](ap) + val bp = b :: p :: HNil + typed[BP](bp) + val apap = a :: p :: a :: p :: HNil + typed[APAP](apap) + val apbp = a :: p :: b :: p :: HNil + typed[APBP](apbp) + val ffff : FFFF = apap + typed[FFFF](ffff) + } + + @Test + def testLength: Unit = { + val l0 = HNil + typed[Nat._0](l0.length) + assertEquals(0, Nat toInt l0.length) + + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + typed[Nat._4](l1.length) + assertEquals(4, Nat toInt l1.length) + + val ap = a :: p :: HNil + typed[Nat._2](ap.length) + assertEquals(2, Nat toInt ap.length) + + val bp = b :: p :: HNil + typed[Nat._2](bp.length) + assertEquals(2, Nat toInt bp.length) + + val apap = a :: p :: a :: p :: HNil + typed[Nat._4](apap.length) + assertEquals(4, Nat toInt apap.length) + + val apbp = a :: p :: b :: p :: HNil + typed[Nat._4](apbp.length) + assertEquals(4, Nat toInt apbp.length) + + val ffff : FFFF = apap + typed[Nat._4](ffff.length) + assertEquals(4, Nat toInt ffff.length) + } + + @Test + def testRuntimeLength: Unit = { + assertEquals(0, HNil.runtimeLength) + assertEquals(1, (123 :: HNil).runtimeLength) + assertEquals(2, ("abc" :: 123 :: HNil).runtimeLength) + } + + @Test + def testRuntimeList: Unit = { + assertEquals(Nil, HNil.runtimeList) + assertEquals(123 :: Nil, (123 :: HNil).runtimeList) + assertEquals("abc" :: 123 :: Nil, ("abc" :: 123 :: HNil).runtimeList) + } + + @Test + def testInitLast: Unit = { + + val lp = apbp.last + assertTypedEquals[Pear](p, lp) + + val iapb = apbp.init + assertTypedEquals[APB](a :: p :: b :: HNil, iapb) + } + + @Test + def testAlign: Unit = { + type M0 = Int :: String :: Boolean :: HNil + type M1 = Int :: Boolean :: String :: HNil + type M2 = String :: Int :: Boolean :: HNil + type M3 = String :: Boolean :: Int :: HNil + type M4 = Boolean :: Int :: String :: HNil + type M5 = Boolean :: String :: Int :: HNil + + val m0 = 13 :: "bar" :: false :: HNil + val m1 = 13 :: false :: "bar" :: HNil + val m2 = "bar" :: 13 :: false :: HNil + val m3 = "bar" :: false :: 13 :: HNil + val m4 = false :: 13 :: "bar" :: HNil + val m5 = false :: "bar" :: 13 :: HNil + + val l = 23 :: "foo" :: true :: HNil + + val a0 = l.align(m0) + assertTypedEquals[M0](23 :: "foo" :: true :: HNil, a0) + + val a1 = l.align(m1) + assertTypedEquals[M1](23 :: true :: "foo" :: HNil, a1) + + val a2 = l.align(m2) + assertTypedEquals[M2]("foo" :: 23 :: true :: HNil, a2) + + val a3 = l.align(m3) + assertTypedEquals[M3]("foo" :: true :: 23 :: HNil, a3) + + val a4 = l.align(m4) + assertTypedEquals[M4](true :: 23 :: "foo" :: HNil, a4) + + val a5 = l.align(m5) + assertTypedEquals[M5](true :: "foo" :: 23 :: HNil, a5) + + val b0 = l.align[M0] + assertTypedEquals[M0](23 :: "foo" :: true :: HNil, b0) + + val b1 = l.align[M1] + assertTypedEquals[M1](23 :: true :: "foo" :: HNil, b1) + + val b2 = l.align[M2] + assertTypedEquals[M2]("foo" :: 23 :: true :: HNil, b2) + + val b3 = l.align[M3] + assertTypedEquals[M3]("foo" :: true :: 23 :: HNil, b3) + + val b4 = l.align[M4] + assertTypedEquals[M4](true :: 23 :: "foo" :: HNil, b4) + + val b5 = l.align[M5] + assertTypedEquals[M5](true :: "foo" :: 23 :: HNil, b5) + + val c0 = (HNil: HNil).align[HNil] + typed[HNil](c0) + + val c1 = (23 :: HNil).align[Int :: HNil] + typed[Int :: HNil](c1) + + val c2 = (23 :: "foo" :: HNil).align[String :: Int :: HNil] + typed[String :: Int :: HNil](c2) + + illTyped(""" + (HNil: HNil).align[Int :: HNil] + """) + + illTyped(""" + (23 :: HNil).align[String :: HNil] + """) + + illTyped(""" + (23 :: "foo" :: HNil).align[String :: String :: HNil] + """) + } + + @Test + def testReverse: Unit = { + val pbpa = apbp.reverse + assertTypedEquals[PBPA](p :: b :: p :: a :: HNil, pbpa) + + val al = a :: HNil + val ral = al.reverse + assertTypedEquals[Apple :: HNil](a :: HNil, ral) + } + + @Test + def testPrepend: Unit = { + val apbp2 = ap ::: bp + assertTypedEquals[APBP](a :: p :: b :: p :: HNil, apbp2) + val apbp2inv = implicitly[Prepend.Aux[AP, BP, APBP]].inverse(apbp2) + assertTypedEquals[AP](ap, apbp2inv._1) + assertTypedEquals[BP](bp, apbp2inv._2) + + typed[Apple](apbp2.head) + typed[Pear](apbp2.tail.head) + typed[Banana](apbp2.tail.tail.head) + typed[Pear](apbp2.tail.tail.tail.head) + + val pabp = ap reverse_::: bp + assertTypedEquals[PABP](p :: a :: b :: p :: HNil, pabp) + + { + // must compile without requiring an implicit Prepend + def prependWithHNil[L <: HList](list: L) = HNil ::: list + def prependToHNil[L <: HList](list: L) = list ::: HNil + + val r1 = prependWithHNil(ap) + assertTypedSame[AP](ap, r1) + val r1inv = implicitly[Prepend.Aux[HNil, AP, AP]].inverse(r1) + assertTypedSame[HNil](HNil, r1inv._1) + assertTypedSame[AP](ap, r1inv._2) + + val r2 = prependToHNil(ap) + assertTypedSame[AP](ap, r2) + val r2inv = implicitly[Prepend.Aux[AP, HNil, AP]].inverse(r2) + assertTypedSame[AP](ap, r2inv._1) + assertTypedSame[HNil](HNil, r2inv._2) + + val r3 = HNil ::: HNil + assertTypedSame[HNil](HNil, r3) + val r3inv = implicitly[Prepend.Aux[HNil, HNil, HNil]].inverse(r3) + assertTypedSame[HNil](HNil, r3inv._1) + assertTypedSame[HNil](HNil, r3inv._2) + + val r4 = prependWithHNil(pabp) + assertTypedSame[PABP](pabp, r4) + val r4inv = implicitly[Prepend.Aux[HNil, PABP, PABP]].inverse(r4) + assertTypedSame[HNil](HNil, r4inv._1) + assertTypedSame[PABP](pabp, r4inv._2) + + val r5 = prependToHNil(pabp) + assertTypedSame[PABP](pabp, r5) + val r5inv = implicitly[Prepend.Aux[PABP, HNil, PABP]].inverse(r5) + assertTypedSame[PABP](pabp, r5inv._1) + assertTypedSame[HNil](HNil, r5inv._2) + } + + { + // must also pass with the default implicit + val r1 = HNil ::: ap + assertTypedSame[AP](ap, r1) + val r1inv = implicitly[Prepend.Aux[HNil, AP, AP]].inverse(r1) + assertTypedSame[HNil](HNil, r1inv._1) + assertTypedSame[AP](ap, r1inv._2) + + val r2 = ap ::: HNil + assertTypedSame[AP](ap, r2) + val r2inv = implicitly[Prepend.Aux[AP, HNil, AP]].inverse(r2) + assertTypedSame[AP](ap, r2inv._1) + assertTypedSame[HNil](HNil, r2inv._2) + + val r4 = HNil ::: pabp + assertTypedSame[PABP](pabp, r4) + val r4inv = implicitly[Prepend.Aux[HNil, PABP, PABP]].inverse(r4) + assertTypedSame[HNil](HNil, r4inv._1) + assertTypedSame[PABP](pabp, r4inv._2) + + val r5 = pabp ::: HNil + assertTypedSame[PABP](pabp, r5) + val r5inv = implicitly[Prepend.Aux[PABP, HNil, PABP]].inverse(r5) + assertTypedSame[PABP](pabp, r5inv._1) + assertTypedSame[HNil](HNil, r5inv._2) + } + + { + // must compile without requiring an implicit ReversePrepend + def reversePrependWithHNil[L <: HList](list: L) = HNil reverse_::: list + def reversePrependToHNil[L <: HList : Reverse](list: L) = list reverse_::: HNil + val r4 = reversePrependWithHNil(ap) + assertTypedSame[AP](ap, r4) + val r5 = reversePrependToHNil(ap) + assertTypedEquals[Pear :: Apple :: HNil](ap.reverse, r5) + val r6 = HNil reverse_::: HNil + assertTypedSame[HNil](HNil, r6) + } + } + + @Test + def testRepeat: Unit = { + val ap2 = ap.repeat[Nat._2] + assertTypedEquals[Apple :: Pear :: Apple :: Pear :: HNil](ap2, a :: p :: a :: p :: HNil) + + val ap4 = ap.repeat[Nat._4] + assertTypedEquals[Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: HNil]( + ap4, a :: p :: a :: p :: a :: p :: a :: p :: HNil + ) + + val ap2_2 = ap2.repeat[Nat._2] + assertTypedEquals[Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: Apple :: Pear :: HNil](ap2_2, ap4) + + { + // repeating 1 times is identity + val ap1 = ap.repeat[Nat._1] + assertTypedEquals[AP](ap, ap1) + } + + { + // can not repeat zero times + illTyped("""ap.repeat[Nat._0]""") + } + + } + + @Test + def testToSizedList: Unit = { + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val hnil = HNil + val snil = hnil.toSized[List] + assertEquals(Nat toInt hnil.length, snil.length) + val expectedUnsized = List.empty[Nothing] + equalInferredTypes(expectedUnsized, snil.unsized) + assertEquals(expectedUnsized, snil.unsized) + + implicitly[ToSized.Aux[HNil, List, Nothing, _0]] + implicitly[ToSized.Aux[HNil, List, Int, _0]] + + { + implicitly[ToSized.Aux[M[Int] :: HNil, List, M[Int], _1]] + implicitly[ToSized.Aux[M[Int] :: HNil, List, M[_], _1]] + } + + val sizedApap = apap.toSized[List] + assertEquals(Nat toInt apap.length, sizedApap.length) + equalInferredTypes(apapList, sizedApap.unsized) + assertEquals(apapList, sizedApap.unsized) + + val sizedApbp = apbp.toSized[List] + assertEquals(Nat toInt apbp.length, sizedApbp.length) + equalInferredTypes(apbpList, sizedApbp.unsized) + assertEquals(apbpList, sizedApbp.unsized) + + val sizedCicscicicd = cicscicicd.toSized[List] + assertEquals(Nat toInt cicscicicd.length, sizedCicscicicd.length) + equalInferredTypes(cicscicicdList, sizedCicscicicd.unsized) + assertEquals(cicscicicdList, sizedCicscicicd.unsized) + + val sizedMimsmimimd = mimsmimimd.toSized[List] + assertEquals(Nat toInt mimsmimimd.length, sizedMimsmimimd.length) + equalInferredTypes(mimsmimimdList, sizedMimsmimimd.unsized) + assertEquals(mimsmimimdList, sizedMimsmimimd.unsized) + + val sizedMimsmimemd = mimsmimemd.toSized[List] + assertEquals(Nat toInt mimsmimemd.length, sizedMimsmimemd.length) + // equalInferredTypes(mimsmimemdList, sizedMimsmimemd.unsized) + typed[List[M[_]]](sizedMimsmimemd.unsized) + assertEquals(mimsmimemdList, sizedMimsmimemd.unsized) + + val sizedM2im2sm2im2im2d = m2im2sm2im2im2d.toSized[List] + assertEquals(Nat toInt m2im2sm2im2im2d.length, sizedM2im2sm2im2im2d.length) + equalInferredTypes(m2im2sm2im2im2dList, sizedM2im2sm2im2im2d.unsized) + assertEquals(m2im2sm2im2im2dList, sizedM2im2sm2im2im2d.unsized) + + val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[List] + assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) + // equalInferredTypes(m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) + assertTypedEquals[List[M2IntStringDoubleBound[_]]]( + m2eim2esm2eim2eem2edList, sizedM2eim2esm2eim2eem2ed.unsized) + } + + @Test + def testToSizedArray: Unit = { + def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = + assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) + + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val hnil = HNil + val snil = hnil.toSized[Array] + assertEquals(Nat toInt hnil.length, snil.length) + val expectedUnsized = Array.empty[Nothing] + equalInferredTypes(expectedUnsized, snil.unsized) + assertArrayEquals2(expectedUnsized, snil.unsized) + + implicitly[ToSized.Aux[HNil, Array, Nothing, _0]] + implicitly[ToSized.Aux[HNil, Array, Int, _0]] + + val sizedApap = apap.toSized[Array] + assertEquals(Nat toInt apap.length, sizedApap.length) + equalInferredTypes(apapArray, sizedApap.unsized) + assertArrayEquals2(apapArray, sizedApap.unsized) + + val sizedApbp = apbp.toSized[Array] + assertEquals(Nat toInt apbp.length, sizedApbp.length) + equalInferredTypes(apbpArray, sizedApbp.unsized) + assertArrayEquals2(apbpArray, sizedApbp.unsized) + + val sizedCicscicicd = cicscicicd.toSized[Array] + assertEquals(Nat toInt cicscicicd.length, sizedCicscicicd.length) + equalInferredTypes(cicscicicdArray, sizedCicscicicd.unsized) + assertArrayEquals2(cicscicicdArray, sizedCicscicicd.unsized) + + val sizedMimsmimimd = mimsmimimd.toSized[Array] + assertEquals(Nat toInt mimsmimimd.length, sizedMimsmimimd.length) + equalInferredTypes(mimsmimimdArray, sizedMimsmimimd.unsized) + assertArrayEquals2(mimsmimimdArray, sizedMimsmimimd.unsized) + + val sizedMimsmimemd = mimsmimemd.toSized[Array] + assertEquals(Nat toInt mimsmimemd.length, sizedMimsmimemd.length) + // equalInferredTypes(mimsmimemdArray, sizedMimsmimemd.unsized) + typed[Array[M[_]]](sizedMimsmimemd.unsized) + assertArrayEquals2(mimsmimemdArray, sizedMimsmimemd.unsized) + + val sizedM2im2sm2im2im2d = m2im2sm2im2im2d.toSized[Array] + assertEquals(Nat toInt m2im2sm2im2im2d.length, sizedM2im2sm2im2im2d.length) + equalInferredTypes(m2im2sm2im2im2dArray, sizedM2im2sm2im2im2d.unsized) + assertArrayEquals2(m2im2sm2im2im2dArray, sizedM2im2sm2im2im2d.unsized) + + val sizedM2eim2esm2eim2eem2ed = m2eim2esm2eim2eem2ed.toSized[Array] + assertEquals(Nat toInt m2eim2esm2eim2eem2ed.length, sizedM2eim2esm2eim2eem2ed.length) + // equalInferredTypes(m2eim2esm2eim2eem2edArray, sizedM2eim2esm2eim2eem2ed.unsized) + typed[Array[M2IntStringDoubleBound[_]]](sizedM2eim2esm2eim2eem2ed.unsized) + assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x: Any), sizedM2eim2esm2eim2eem2ed.unsized.map(x => x: Any)) + } + + @Test + def testUnifier: Unit = { + def lub[X, Y, L](x : X, y : Y)(implicit lb : Lub[X, Y, L]) : (L, L) = (lb.left(x), lb.right(y)) + + val u21 = lub(a, a) + typed[(Apple, Apple)](u21) + val u22 = lub(a, p) + typed[(Fruit, Fruit)](u22) + val u23 = lub(a, f) + typed[(Fruit, Fruit)](u23) + val u24 = lub(p, a) + typed[(Fruit, Fruit)](u24) + val u25 = lub(p, p) + typed[(Pear, Pear)](u25) + val u26 = lub(f, f) + typed[(Fruit, Fruit)](u26) + val u27 = lub(f, a) + typed[(Fruit, Fruit)](u27) + val u28 = lub(f, p) + typed[(Fruit, Fruit)](u28) + val u29 = lub(f, f) + typed[(Fruit, Fruit)](u29) + + implicitly[Lub[HNil, HNil, HNil]] + implicitly[Lub[Apple :: HNil, Apple :: HNil, Apple :: HNil]] + implicitly[Lub[Fruit :: Pear :: HNil, Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil]] + implicitly[Lub[Apple :: Pear :: HNil, Pear :: Apple :: HNil, Fruit :: Fruit :: HNil]] + implicitly[Lub[ISII, IIII, IYII]] + + val u31 = lub(HNil, HNil) + typed[(HNil, HNil)](u31) + val u32 = lub(a :: HNil, a :: HNil) + typed[(Apple :: HNil, Apple :: HNil)](u32) + val u33 = lub(f :: p :: HNil, f :: f :: HNil) + typed[(Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil)](u33) + val u34 = lub(a :: p :: HNil, p :: a :: HNil) + typed[(Fruit :: Fruit :: HNil, Fruit :: Fruit :: HNil)](u34) + val u35 = lub(1 :: "two" :: 3 :: 4 :: HNil, 1 :: 2 :: 3 :: 4 :: HNil) + typed[(Int :: Any :: Int :: Int :: HNil, Int :: Any :: Int :: Int :: HNil)](u35) + + implicitly[Unifier.Aux[Apple :: HNil, Apple :: HNil]] + implicitly[Unifier.Aux[Fruit :: Pear :: HNil, Fruit :: Fruit :: HNil]] + implicitly[Unifier.Aux[Apple :: Pear :: HNil, Fruit :: Fruit :: HNil]] + + implicitly[Unifier.Aux[Int :: String :: Int :: Int :: HNil, YYYY]] + + val uapap = implicitly[Unifier.Aux[Apple :: Pear :: Apple :: Pear :: HNil, FFFF]] + val unified1 = uapap(apap) + typed[FFFF](unified1) + val unified2 = apap.unify + typed[FFFF](unified2) + + val ununified1 = unified2.cast[APAP] + assertTrue(ununified1.isDefined) + typed[APAP](ununified1.get) + val ununified2 = unified2.cast[APBP] + assertFalse(ununified2.isDefined) + typed[Option[APBP]](ununified2) + + def getUnifier[L <: HList, Out <: HList](l : L)(implicit u : Unifier.Aux[L, Out]) = u + + val u2 = getUnifier(a :: HNil) + typed[Unifier.Aux[Apple :: HNil, Apple :: HNil]](u2) + val u3 = getUnifier(a :: a :: HNil) + typed[Unifier.Aux[Apple :: Apple :: HNil, Apple :: Apple :: HNil]](u3) + val u4 = getUnifier(a :: a :: a :: HNil) + typed[Unifier.Aux[Apple :: Apple :: Apple :: HNil, Apple :: Apple :: Apple :: HNil]](u4) + val u5 = getUnifier(a :: a :: a :: a :: HNil) + typed[Unifier.Aux[Apple :: Apple :: Apple :: Apple :: HNil, Apple :: Apple :: Apple :: Apple :: HNil]](u5) + val u6 = getUnifier(a :: p :: HNil) + //typed[Unifier.Aux[Apple :: Pear :: HNil, Fruit :: Fruit :: HNil]](u6) + val u7 = getUnifier(a :: f :: HNil) + typed[Unifier.Aux[Apple :: Fruit :: HNil, Fruit :: Fruit :: HNil]](u7) + val u8 = getUnifier(f :: a :: HNil) + typed[Unifier.Aux[Fruit :: Apple :: HNil, Fruit :: Fruit :: HNil]](u8) + val u9a = getUnifier(a :: f :: HNil) + typed[Unifier.Aux[Apple :: Fruit :: HNil, FF]](u9a) + val u9b = getUnifier(a :: p :: HNil) + typed[Unifier.Aux[Apple :: Pear :: HNil, PWS :: PWS :: HNil]](u9b) + val u10 = getUnifier(apap) + typed[Unifier.Aux[APAP, PWS :: PWS :: PWS :: PWS :: HNil]](u10) + val u11 = getUnifier(apbp) + typed[Unifier.Aux[APBP, PWS :: PWS :: PWS :: PWS :: HNil]](u11) + + val invar1 = Set(23) :: Set("foo") :: HNil + val uinvar1 = invar1.unify + typed[Set[_ >: Int with String] :: Set[_ >: Int with String] :: HNil](uinvar1) + + // Unifying three or more elements which have an invariant outer type constructor and differing type + // arguments fails, presumably due to a failure to compute a sensible LUB. + //val invar2 = Set(23) :: Set("foo") :: Set(true) :: HNil + //val uinvar2 = invar.unify + } + + @Test + def testSubtypeUnifier: Unit = { + val fruits : Apple :: Pear :: Fruit :: HNil = a :: p :: f :: HNil + typed[Fruit :: Fruit :: Fruit :: HNil](fruits.unifySubtypes[Fruit]) + typed[Apple :: Pear :: Fruit :: HNil](fruits.unifySubtypes[Apple]) + assertEquals(a :: p :: f :: HNil, fruits.unifySubtypes[Fruit].filter[Fruit]) + + val stuff : Apple :: String :: Pear :: HNil = a :: "foo" :: p :: HNil + typed[Fruit :: String :: Fruit :: HNil](stuff.unifySubtypes[Fruit]) + assertEquals(HNil, stuff.filter[Fruit]) + assertEquals(a :: p :: HNil, stuff.unifySubtypes[Fruit].filter[Fruit]) + } + + @Test + def testToTraversableList: Unit = { + val r1 = HNil.to[List] + assertTypedEquals[List[Nothing]](Nil, r1) + + ToList[HNil, Nothing] + ToList[HNil, Int] + + { + implicitly[ToTraversable.Aux[M[Int] :: HNil, List, M[Int]]] + implicitly[ToTraversable.Aux[M[Int] :: HNil, List, M[_]]] + } + + val r2 = apap.to[List] + assertTypedEquals[List[Fruit]](List(a, p, a, p), r2) + + val fruits2 = apbp.to[List] + assertTypedEquals[List[Fruit]](List(a, p, b, p), fruits2) + + val fruits3 = fruits2.toHList[APBP] + assertTrue(fruits3.isDefined) + assertTypedEquals[APBP](apbp, fruits3.get) + + val stuff = (1 :: "foo" :: 2 :: 3 :: HNil).to[List] + assertTypedEquals[List[Any]](List(1, "foo", 2, 3), stuff) + + val stuff2 = stuff.toHList[ISII] + assertTrue(stuff2.isDefined) + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) + + val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + val l7 = l4 map isDefined + assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) + + val ll2 = l7.to[List] + typed[Boolean](ll2.head) + + val moreStuff = (a :: "foo" :: p :: HNil).to[List] + typed[List[Any]](moreStuff) + + + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val ctv = cicscicicd.to[List] + equalInferredTypes(cicscicicdList, ctv) + assertTypedEquals[List[Ctv[Int with String with Double]]](cicscicicdList, ctv) + + val m = mimsmimimd.to[List] + equalInferredTypes(mimsmimimdList, m) + assertTypedEquals[List[M[_ >: Int with String with Double]]](mimsmimimdList, m) + + val mWithEx = mimsmimemd.to[List] + // equalType(mimsmimemdList, mWithEx) + assertTypedEquals[List[M[_]]](mimsmimemdList, mWithEx) + + val m2 = m2im2sm2im2im2d.to[List] + equalInferredTypes(m2im2sm2im2im2dList, m2) + assertTypedEquals[List[M2[_ >: Int with String with Double, Unit]]](m2im2sm2im2im2dList, m2) + + val m2e = m2eim2esm2eim2eem2ed.to[List] + // equalType(m2eim2esm2eim2eem2edList, m2e) + assertTypedEquals[List[M2[_ >: Int with String with Double, _]]](m2eim2esm2eim2eem2edList, m2e) + } + + @Test + def testToPreciseList: Unit = { + val r1 = HNil.toCoproduct[List] + assertTypedEquals[List[CNil]](Nil, r1) + + val r2 = ap.toCoproduct[List] + assertTypedEquals[List[APc]](List(Coproduct[APc](a), Coproduct[APc](p)), r2) + + val r3 = apap.toCoproduct[List] + assertTypedEquals[List[APc]](List(Coproduct[APc](a), Coproduct[APc](p), Coproduct[APc](a), Coproduct[APc](p)), r3) + + val r4 = apbp.toCoproduct[Vector] + assertTypedEquals[Vector[ABPc]](Vector[ABPc](Coproduct[ABPc](a), Coproduct[ABPc](p), Coproduct[ABPc](b), Coproduct[ABPc](p)), r4) + + def equalInferedCoproducts[A <: Coproduct, B <: Coproduct](a: A, b: B)(implicit bInA: ops.coproduct.Basis[A, B], aInB: ops.coproduct.Basis[B, A]): Unit = {} + val abpc = Coproduct[ABPc](a) + + val r5 = (a :: b :: a :: p :: b :: a :: HNil).toCoproduct[Set] + equalInferedCoproducts(abpc, r5.head) + + val r6 = (p :: a :: a :: p :: p :: b :: HNil).toCoproduct[Set] + equalInferedCoproducts(abpc, r6.head) + + val r7 = (a :: b :: p :: HNil).toCoproduct[Seq] + equalInferedCoproducts(abpc, r7.head) + + + val r8 = (a :: b :: HNil).toCoproduct[Seq] + + illTyped{ + """equalInferedCoproducts(abpc, r8.head)""" + } + + illTyped{ + """(1 :: "foo" :: HNil).toPrecise[Array]""" + } + + } + + @Test + def testToList: Unit = { + val r1 = HNil.toList + assertTypedEquals[List[Nothing]](Nil, r1) + + implicitly[ToTraversable.Aux[HNil, List, Nothing]] + implicitly[ToTraversable.Aux[HNil, List, Int]] + + { + val l1 = (mi :: HNil).toList[M[Int]] + val l2 = (mi :: HNil).toList[M[_]] + + assertTypedEquals[List[M[Int]]](List(mi), l1) + assertTypedEquals[List[M[_]]](List(mi), l2) + } + + val fruits1 = apap.toList + assertTypedEquals[List[Fruit]](List(a, p, a, p), fruits1) + + val fruits2 = apbp.toList + assertTypedEquals[List[Fruit]](List(a, p, b, p), fruits2) + + val fruits3 = fruits2.toHList[APBP] + assertTrue(fruits3.isDefined) + assertTypedEquals[APBP](apbp, fruits3.get) + + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + + val stuff = l1.toList + assertTypedEquals[List[Any]](List(1, "foo", 2, 3), stuff) + + val stuff2 = stuff.toHList[ISII] + assertTrue(stuff2.isDefined) + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) + + val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + val l7 = l4 map isDefined + assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) + + val ll2 = l7.toList + typed[Boolean](ll2.head) + + val moreStuff = (a :: "foo" :: p :: HNil).toList + typed[List[Any]](moreStuff) + + + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val ctv = cicscicicd.toList + equalInferredTypes(cicscicicdList, ctv) + assertTypedEquals[List[Ctv[Int with String with Double]]](cicscicicdList, ctv) + + val m = mimsmimimd.toList + equalInferredTypes(mimsmimimdList, m) + assertTypedEquals[List[M[_ >: Int with String with Double]]](mimsmimimdList, m) + + // With existentials, it gets more tricky + val mWithEx = mimsmimemd.toList + // Compiler fails complaining that it + // Cannot prove that List[HListTests.this.M[_ >: Double with _$1 with Int with String]] =:= List[HListTests.this.M[_]] + // equalType(mimsmimemdList, mWithEx) + assertTypedEquals[List[M[_]]](mimsmimemdList, mWithEx) + + // Second order higher kinded types are ok... + val m2 = m2im2sm2im2im2d.toList + equalInferredTypes(m2im2sm2im2im2dList, m2) + assertTypedEquals[List[M2[_ >: Int with String with Double, Unit]]](m2im2sm2im2im2dList, m2) + + // ...as long as existentials are not involved. + val m2e = m2eim2esm2eim2eem2ed.toList + // Compiler complains that it + // Cannot prove that List[HListTests.this.M2[_ >: Double with Int with Int with String with Int, _ >: _$5 with _$3 with _$3 with _$4 with _$3]] =:= List[HListTests.this.M2[_35,_36] forSome { type _$10; type _$9; type _34 >: _$10 with _$9; type _$8; type _$7; type _32 >: _$8 with _$7; type _35 >: Double with Int with Int with String; type _36 >: _34 with _32 }] + // equalType(m2eim2esm2eim2eem2edList, m2e) + assertTypedEquals[List[M2[_ >: Int with String with Double, _]]](m2eim2esm2eim2eem2edList, m2e) + } + + @Test + def testToTraversableArray: Unit = { + def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = + assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) + + val empty = HNil.to[Array] + typed[Array[Nothing]](empty) + assertArrayEquals2(Array[Nothing](), empty) + + implicitly[ToTraversable.Aux[HNil, Array, Nothing]] + implicitly[ToTraversable.Aux[HNil, Array, Int]] + + { + implicitly[ToTraversable.Aux[M[Int] :: HNil, Array, M[Int]]] + implicitly[ToTraversable.Aux[M[Int] :: HNil, Array, M[_]]] + } + + val fruits1 = apap.to[Array].map(x => x : Fruit) // Default inferred type is too precise + // (Product with Serializable with Fruit) + typed[Array[Fruit]](fruits1) + assertArrayEquals2(Array[Fruit](a, p, a, p), fruits1) + + val fruits2 = apbp.to[Array].map(x => x : Fruit) + typed[Array[Fruit]](fruits2) + assertArrayEquals2(Array[Fruit](a, p, b, p), fruits2) + + val fruits3 = fruits2.toHList[APBP] + assertTrue(fruits3.isDefined) + assertTypedEquals[APBP](apbp, fruits3.get) + + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + + val stuff = l1.to[Array] + typed[Array[Any]](stuff) + assertArrayEquals2(Array(1, "foo", 2, 3), stuff) + + val stuff2 = stuff.toHList[ISII] + assertTrue(stuff2.isDefined) + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) + + val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + val l7 = l4 map isDefined + assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) + + val ll2 = l7.to[Array] + typed[Boolean](ll2(0)) + + val moreStuff = (a :: "foo" :: p :: HNil).to[Array].map(x => x : AnyRef) + typed[Array[AnyRef]](moreStuff) + assertArrayEquals2(Array[AnyRef](a, "foo", p), moreStuff) + + + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val ctv = cicscicicd.to[Array] + equalInferredTypes(cicscicicdArray, ctv) + typed[Array[Ctv[Int with String with Double]]](ctv) + assertArrayEquals2(cicscicicdArray, ctv) + + val m = mimsmimimd.to[Array] + equalInferredTypes(mimsmimimdArray, m) + typed[Array[MIntStringDoubleBound]](m) + assertArrayEquals2(mimsmimimdArray, m) + + val mWithEx = mimsmimemd.to[Array] + // equalType(mimsmimemdArray, mWithEx) + typed[Array[M[_]]](mWithEx) + assertArrayEquals2(mimsmimemdArray, mWithEx) + + val m2 = m2im2sm2im2im2d.to[Array] + equalInferredTypes(m2im2sm2im2im2dArray, m2) + typed[Array[M2IntStringDoubleBound[Unit]]](m2) + assertArrayEquals2(m2im2sm2im2im2dArray, m2) + + val m2e = m2eim2esm2eim2eem2ed.to[Array] + // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) + typed[Array[M2IntStringDoubleBound[_]]](m2e) + assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) + } + + @Test + def testToArray: Unit = { + def assertArrayEquals2[T](arr1 : Array[T], arr2 : Array[T]) = + assertArrayEquals(arr1.asInstanceOf[Array[Object]], arr2.asInstanceOf[Array[Object]]) + + val empty = HNil.toArray + typed[Array[Nothing]](empty) + assertArrayEquals2(Array[Nothing](), empty) + + ToArray[HNil, Nothing] + ToArray[HNil, Int] + + { + val a1 = (mi :: HNil).toArray[M[Int]] + val a2 = (mi :: HNil).toArray[M[_]] + + typed[Array[M[Int]]](a1) + typed[Array[M[_]]](a2) + assertArrayEquals2(Array[M[Int]](mi), a1) + assertArrayEquals2(Array[M[_]](mi), a2) + } + + val fruits1 = apap.toArray[Fruit] + typed[Array[Fruit]](fruits1) + assertArrayEquals2(Array[Fruit](a, p, a, p), fruits1) + + val fruits2 = apbp.toArray[Fruit] + typed[Array[Fruit]](fruits2) + assertArrayEquals2(Array[Fruit](a, p, b, p), fruits2) + + val fruits3 = fruits2.toHList[APBP] + assertTrue(fruits3.isDefined) + assertTypedEquals[APBP](apbp, fruits3.get) + + val l1 = 1 :: "foo" :: 2 :: 3 :: HNil + + val stuff = l1.toArray + typed[Array[AnyOrMatchable]](stuff) + assertArrayEquals2(Array(1, "foo", 2, 3), stuff) + + val ssl = "foo" :: "bar" :: 1L :: HNil + val ssla = ssl.toArray + typed[Array[AnyOrMatchable]](ssla) + assertArrayEquals2(Array("foo", "bar", 1L), ssla) + + val stuff2 = stuff.toHList[ISII] + assertTrue(stuff2.isDefined) + assertTypedEquals[ISII](1 :: "foo" :: 2 :: 3 :: HNil, stuff2.get) + + val l4 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + val l7 = l4 map isDefined + assertTypedEquals[BBBB](true :: true :: true :: true :: HNil, l7) + + val ll2 = l7.toArray + typed[Boolean](ll2(0)) + + val moreStuff = (a :: "foo" :: p :: HNil).toArray[AnyRef] + typed[Array[AnyRef]](moreStuff) + assertArrayEquals2(Array[AnyRef](a, "foo", p), moreStuff) + + + def equalInferredTypes[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = {} + + val ctv = cicscicicd.toArray + equalInferredTypes(cicscicicdArray, ctv) + typed[Array[Ctv[Int with String with Double]]](ctv) + assertArrayEquals2(cicscicicdArray, ctv) + + val m = mimsmimimd.toArray + equalInferredTypes(mimsmimimdArray, m) + typed[Array[MIntStringDoubleBound]](m) + assertArrayEquals2(mimsmimimdArray, m) + + val mWithEx = mimsmimemd.toArray[M[_]] + // equalType(mimsmimemdArray, mWithEx) + typed[Array[M[_]]](mWithEx) + assertArrayEquals2(mimsmimemdArray, mWithEx) + + val m2 = m2im2sm2im2im2d.toArray + equalInferredTypes(m2im2sm2im2im2dArray, m2) + typed[Array[M2IntStringDoubleBound[Unit]]](m2) + assertArrayEquals2(m2im2sm2im2im2dArray, m2) + + val m2e = m2eim2esm2eim2eem2ed.toArray + // equalInferredTypes(m2eim2esm2eim2eem2edArray, m2e) + typed[Array[M2IntStringDoubleBound[_]]](m2e) + assertArrayEquals2(m2eim2esm2eim2eem2edArray.map(x => x : Any), m2e.map(x => x : Any)) + } + + @Test + def testFoldMap: Unit = { + implicitly[Mapper.Aux[isDefined.type, HNil, HNil]] + implicitly[Mapper.Aux[isDefined.type, Option[Int] :: HNil, Boolean :: HNil]] + + val tl1 = Option(1) :: Option("foo") :: Option(2) :: Option(3) :: HNil + val tl2 = Option(1) :: Option("foo") :: (None : Option[Int]) :: Option(3) :: HNil + + val mlfl1 = (tl1 map isDefined).toList.foldLeft(true)(_ && _) + assertTrue(mlfl1) + val mlfl2 = (tl2 map isDefined).toList.foldLeft(true)(_ && _) + assertFalse(mlfl2) + + val fl1 = tl1.foldMap(true)(isDefined)(_ && _) + assertTrue(fl1) + val fl2 = tl2.foldMap(true)(isDefined)(_ && _) + assertFalse(fl2) + } + + @Test + def testAt: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val at0 = sn1(_0) + assertTypedEquals[Int](23, at0) + + val at1 = sn1(_1) + typed[Double](at1) + assertEquals(3.0, at1, Double.MinPositiveValue) + + val at2 = sn1(_2) + assertTypedEquals[String]("foo", at2) + + val at3 = sn1(_3) + assertTypedEquals[Unit]((), at3) + + val at4 = sn1(_4) + assertTypedEquals[String]("bar", at4) + + val at5 = sn1(_5) + assertTypedEquals[Boolean](true, at5) + + val at6 = sn1(_6) + assertTypedEquals[Long](5L, at6) + + val sn2 = + 0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: + 10 :: 11 :: 12 :: 13 :: 14 :: 15 :: 16 :: 17 :: 18 :: 19 :: + 20 :: 21 :: 22 :: HNil + + val at22 = sn2(_22) + assertTypedEquals[Int](22, at22) + } + + @Test + def testAtLiteral: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val at0 = sn1(0) + assertTypedEquals[Int](23, at0) + + val at1 = sn1(1) + typed[Double](at1) + assertEquals(3.0, at1, Double.MinPositiveValue) + + val at2 = sn1(2) + assertTypedEquals[String]("foo", at2) + + val at3 = sn1(3) + assertTypedEquals[Unit]((), at3) + + val at4 = sn1(4) + assertTypedEquals[String]("bar", at4) + + val at5 = sn1(5) + assertTypedEquals[Boolean](true, at5) + + val at6 = sn1(6) + assertTypedEquals[Long](5L, at6) + + val sn2 = + 0 :: 1 :: 2 :: 3 :: 4 :: 5 :: 6 :: 7 :: 8 :: 9 :: + 10 :: 11 :: 12 :: 13 :: 14 :: 15 :: 16 :: 17 :: 18 :: 19 :: + 20 :: 21 :: 22 :: HNil + + val at22 = sn2(22) + assertTypedEquals[Int](22, at22) + } + + @Test + def testTakeDrop: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val r1 = sn1.take(_0) + assertTypedEquals[HNil](HNil, r1) + + val r2 = sn1.drop(_0) + assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( + 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r2) + + val r3 = sn1.take(_2) + assertTypedEquals[Int :: Double :: HNil](23 :: 3.0 :: HNil, r3) + + val r4 = sn1.drop(_2) + assertTypedEquals[String :: Unit :: String :: Boolean :: Long :: HNil]( + "foo" :: () :: "bar" :: true :: 5L :: HNil, r4) + + val r5 = sn1.take(_7) + assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( + 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r5) + + val r6 = sn1.drop(_7) + assertTypedEquals[HNil](HNil, r6) + } + + @Test + def testTakeDropLiteral: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val r1 = sn1.take(0) + assertTypedEquals[HNil](HNil, r1) + + val r2 = sn1.drop(0) + assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( + 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r2) + + val r3 = sn1.take(2) + assertTypedEquals[Int :: Double :: HNil](23 :: 3.0 :: HNil, r3) + + val r4 = sn1.drop(2) + assertTypedEquals[String :: Unit :: String :: Boolean :: Long :: HNil]( + "foo" :: () :: "bar" :: true :: 5L :: HNil, r4) + + val r5 = sn1.take(7) + assertTypedEquals[Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil]( + 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil, r5) + + val r6 = sn1.drop(7) + assertTypedEquals[HNil](HNil, r6) + } + + @Test + def testSplit: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val sni0 = sn1.split(_0) + typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni0) + val sni1 = sn1.split(_1) + typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni1) + val sni2 = sn1.split(_2) + typed[((Int :: Double :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](sni2) + val sni3 = sn1.split(_3) + typed[((Int :: Double :: String :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](sni3) + val sni4 = sn1.split(_4) + typed[((Int :: Double :: String :: Unit :: HNil), (String :: Boolean :: Long :: HNil))](sni4) + val sni5 = sn1.split(_5) + typed[((Int :: Double :: String :: Unit :: String :: HNil), (Boolean :: Long :: HNil))](sni5) + val sni6 = sn1.split(_6) + typed[((Int :: Double :: String :: Unit :: String :: Boolean :: HNil), (Long :: HNil))](sni6) + val sni7 = sn1.split(_7) + typed[((Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil), HNil)](sni7) + + val snri0 = sn1.reverse_split(_0) + typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri0) + val snri1 = sn1.reverse_split(_1) + typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri1) + val snri2 = sn1.reverse_split(_2) + typed[((Double :: Int :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](snri2) + val snri3 = sn1.reverse_split(_3) + typed[((String :: Double :: Int :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](snri3) + val snri4 = sn1.reverse_split(_4) + typed[((Unit :: String :: Double :: Int :: HNil), (String :: Boolean :: Long :: HNil))](snri4) + val snri5 = sn1.reverse_split(_5) + typed[((String :: Unit :: String :: Double :: Int :: HNil), (Boolean :: Long :: HNil))](snri5) + val snri6 = sn1.reverse_split(_6) + typed[((Boolean :: String :: Unit :: String :: Double :: Int :: HNil), (Long :: HNil))](snri6) + val snri7 = sn1.reverse_split(_7) + typed[((Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil), HNil)](snri7) + } + + @Test + def testSplitLiteral: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val sni0 = sn1.split(0) + typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni0) + val sni1 = sn1.split(1) + typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](sni1) + val sni2 = sn1.split(2) + typed[((Int :: Double :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](sni2) + val sni3 = sn1.split(3) + typed[((Int :: Double :: String :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](sni3) + val sni4 = sn1.split(4) + typed[((Int :: Double :: String :: Unit :: HNil), (String :: Boolean :: Long :: HNil))](sni4) + val sni5 = sn1.split(5) + typed[((Int :: Double :: String :: Unit :: String :: HNil), (Boolean :: Long :: HNil))](sni5) + val sni6 = sn1.split(6) + typed[((Int :: Double :: String :: Unit :: String :: Boolean :: HNil), (Long :: HNil))](sni6) + val sni7 = sn1.split(7) + typed[((Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil), HNil)](sni7) + + val snri0 = sn1.reverse_split(0) + typed[(HNil, (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri0) + val snri1 = sn1.reverse_split(1) + typed[((Int :: HNil), (Double :: String :: Unit :: String :: Boolean :: Long :: HNil))](snri1) + val snri2 = sn1.reverse_split(2) + typed[((Double :: Int :: HNil), (String :: Unit :: String :: Boolean :: Long :: HNil))](snri2) + val snri3 = sn1.reverse_split(3) + typed[((String :: Double :: Int :: HNil), (Unit :: String :: Boolean :: Long :: HNil))](snri3) + val snri4 = sn1.reverse_split(4) + typed[((Unit :: String :: Double :: Int :: HNil), (String :: Boolean :: Long :: HNil))](snri4) + val snri5 = sn1.reverse_split(5) + typed[((String :: Unit :: String :: Double :: Int :: HNil), (Boolean :: Long :: HNil))](snri5) + val snri6 = sn1.reverse_split(6) + typed[((Boolean :: String :: Unit :: String :: Double :: Int :: HNil), (Long :: HNil))](snri6) + val snri7 = sn1.reverse_split(7) + typed[((Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil), HNil)](snri7) + } + + @Test + def testSplitP: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val sni0 = sn1.splitP(_0) + typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni0) + val sni1 = sn1.splitP(_1) + typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni1) + val sni2 = sn1.splitP(_2) + typed[(Int :: Double :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni2) + val sni3 = sn1.splitP(_3) + typed[(Int :: Double :: String :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni3) + val sni4 = sn1.splitP(_4) + typed[(Int :: Double :: String :: Unit :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](sni4) + val sni5 = sn1.splitP(_5) + typed[(Int :: Double :: String :: Unit :: String :: HNil) :: (Boolean :: Long :: HNil) :: HNil](sni5) + val sni6 = sn1.splitP(_6) + typed[(Int :: Double :: String :: Unit :: String :: Boolean :: HNil) :: (Long :: HNil) :: HNil](sni6) + val sni7 = sn1.splitP(_7) + typed[(Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: (HNil) :: HNil](sni7) + + val snri0 = sn1.reverse_splitP(_0) + typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri0) + val snri1 = sn1.reverse_splitP(_1) + typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri1) + val snri2 = sn1.reverse_splitP(_2) + typed[(Double :: Int :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri2) + val snri3 = sn1.reverse_splitP(_3) + typed[(String :: Double :: Int :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri3) + val snri4 = sn1.reverse_splitP(_4) + typed[(Unit :: String :: Double :: Int :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](snri4) + val snri5 = sn1.reverse_splitP(_5) + typed[(String :: Unit :: String :: Double :: Int :: HNil) :: (Boolean :: Long :: HNil) :: HNil](snri5) + val snri6 = sn1.reverse_splitP(_6) + typed[(Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (Long :: HNil) :: HNil](snri6) + val snri7 = sn1.reverse_splitP(_7) + typed[(Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (HNil) :: HNil](snri7) + } + + @Test + def testSplitPLiteral: Unit = { + val sn1 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val sni0 = sn1.splitP(0) + typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni0) + val sni1 = sn1.splitP(1) + typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni1) + val sni2 = sn1.splitP(2) + typed[(Int :: Double :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni2) + val sni3 = sn1.splitP(3) + typed[(Int :: Double :: String :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](sni3) + val sni4 = sn1.splitP(4) + typed[(Int :: Double :: String :: Unit :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](sni4) + val sni5 = sn1.splitP(5) + typed[(Int :: Double :: String :: Unit :: String :: HNil) :: (Boolean :: Long :: HNil) :: HNil](sni5) + val sni6 = sn1.splitP(6) + typed[(Int :: Double :: String :: Unit :: String :: Boolean :: HNil) :: (Long :: HNil) :: HNil](sni6) + val sni7 = sn1.splitP(7) + typed[(Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: (HNil) :: HNil](sni7) + + val snri0 = sn1.reverse_splitP(0) + typed[(HNil) :: (Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri0) + val snri1 = sn1.reverse_splitP(1) + typed[(Int :: HNil) :: (Double :: String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri1) + val snri2 = sn1.reverse_splitP(2) + typed[(Double :: Int :: HNil) :: (String :: Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri2) + val snri3 = sn1.reverse_splitP(3) + typed[(String :: Double :: Int :: HNil) :: (Unit :: String :: Boolean :: Long :: HNil) :: HNil](snri3) + val snri4 = sn1.reverse_splitP(4) + typed[(Unit :: String :: Double :: Int :: HNil) :: (String :: Boolean :: Long :: HNil) :: HNil](snri4) + val snri5 = sn1.reverse_splitP(5) + typed[(String :: Unit :: String :: Double :: Int :: HNil) :: (Boolean :: Long :: HNil) :: HNil](snri5) + val snri6 = sn1.reverse_splitP(6) + typed[(Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (Long :: HNil) :: HNil](snri6) + val snri7 = sn1.reverse_splitP(7) + typed[(Long :: Boolean :: String :: Unit :: String :: Double :: Int :: HNil) :: (HNil) :: HNil](snri7) + } + + @Test + def testSelect: Unit = { + val sl = 1 :: true :: "foo" :: 2.0 :: HNil + val si = sl.select[Int] + assertTypedEquals[Int](1, si) + + val sb = sl.select[Boolean] + assertTypedEquals[Boolean](true, sb) + + val ss = sl.select[String] + assertTypedEquals[String]("foo", ss) + + val sd = sl.select[Double] + assertEquals(2.0, sd, Double.MinPositiveValue) + } + @Test + def testSelectRange: Unit = { + val sl = 1 :: true :: "foo" :: 2.0 :: HNil + + val sl1 = sl.selectRange[_0,_0] + val sl1i = sl.selectRange(0,0) + assertTypedEquals[HNil](HNil, sl1) + assertTypedEquals[HNil](HNil, sl1i) + + val sl2 = sl.selectRange[_1,_1] + val sl2i = sl.selectRange(1,1) + assertTypedEquals[HNil](HNil, sl2) + assertTypedEquals[HNil](HNil, sl2i) + + val sl3 = sl.selectRange[_0,_2] + val sl3i = sl.selectRange(0,2) + assertTypedEquals[Int::Boolean::HNil](1::true::HNil, sl3) + assertTypedEquals[Int::Boolean::HNil](1::true::HNil, sl3i) + + val sl4 = sl.selectRange[_2,_4] + val sl4i = sl.selectRange(2,4) + assertTypedEquals[String::Double::HNil]("foo"::2.0::HNil, sl4) + assertTypedEquals[String::Double::HNil]("foo"::2.0::HNil, sl4i) + + val sl5 = sl.selectRange[_0,_4] + val sl5i = sl.selectRange(0,4) + assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, sl5) + assertTypedEquals[Int::Boolean::String::Double::HNil](1 :: true :: "foo" :: 2.0 :: HNil, sl5i) + + } + + @Test + def testSelectFirst: Unit = { + val sl = 1 :: true :: "foo" :: 2.0 :: HNil + + val si = sl.selectFirst[Int::HNil] + assertTypedEquals[Int](1, si) + + val sb = sl.selectFirst[Boolean::HNil] + assertTypedEquals[Boolean](true, sb) + + val ss = sl.selectFirst[String::HNil] + assertTypedEquals[String]("foo", ss) + + val sd = sl.selectFirst[Double::HNil] + assertEquals(2.0, sd, Double.MinPositiveValue) + + val sib = sl.selectFirst[Int::Boolean::HNil] + assertTypedEquals[Int](1, sib) + + val sulb = sl.selectFirst[Unit::Long::Boolean::HNil] + assertTypedEquals[Boolean](true, sulb) + + val ssbi = sl.selectFirst[String::Boolean::Int::HNil] + assertTypedEquals[String]("foo", ssbi) + } + + @Test + def testFilter: Unit = { + val l1 = 1 :: 2 :: HNil + val f1 = l1.filter[Int] + assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f1) + + val l2 = 1 :: true :: "foo" :: 2 :: HNil + val f2 = l2.filter[Int] + assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f2) + + typed[HNil](l2.filter[Double]) + } + + @Test + def testFilterNot: Unit = { + val l1 = 1 :: 2 :: HNil + val f1 = l1.filterNot[String] + assertTypedEquals[Int :: Int :: HNil](1 :: 2 :: HNil, f1) + + val l2 = 1 :: true :: "foo" :: 2 :: HNil + val f2 = l2.filterNot[String] + assertTypedEquals[Int :: Boolean :: Int :: HNil](1 :: true :: 2 :: HNil, f2) + + typed[HNil](l2.filter[Double]) + } + + @Test + def testPartition: Unit = { + val l1 = 1 :: 2 :: HNil + val l2 = 1 :: true :: "foo" :: 2 :: HNil + + val r1 = l1.partition[Int] + assertTypedEquals[(Int :: Int :: HNil, HNil)]((1 :: 2 :: HNil, HNil), r1) + + val r2 = l1.partitionP[Int] + assertTypedEquals[(Int :: Int :: HNil) :: HNil :: HNil]((1 :: 2 :: HNil) :: HNil :: HNil, r2) + + val r3 = l2.partition[Int] + assertTypedEquals[(Int :: Int :: HNil, Boolean :: String :: HNil)]((1 :: 2 :: HNil, true :: "foo" :: HNil), r3) + + val r4 = l2.partitionP[Int] + assertTypedEquals[(Int :: Int :: HNil) :: (Boolean :: String :: HNil) :: HNil]( + (1 :: 2 :: HNil) :: (true :: "foo" :: HNil) :: HNil, r4 + ) + } + + @Test + def testReplace: Unit = { + val sl = 1 :: true :: "foo" :: 2.0 :: HNil + + val (i, r1) = sl.replace(23) + assertTypedEquals[Int](1, i) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](23 :: true :: "foo" :: 2.0 :: HNil, r1) + + val (b, r2) = sl.replace(false) + assertTypedEquals[Boolean](true, b) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: false :: "foo" :: 2.0 :: HNil, r2) + + val (s, r3) = sl.replace("bar") + assertTypedEquals[String]("foo", s) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "bar" :: 2.0 :: HNil, r3) + + val (d, r4) = sl.replace(3.0) + typed[Double](d) + assertEquals(2.0, d, Double.MinPositiveValue) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "foo" :: 3.0 :: HNil, r4) + + val (i2, r5) = sl.replaceType[Int]('*') + typed[Char](r5(0)) + assertTypedEquals[Int](1, i2) + assertTypedEquals[Char :: Boolean :: String :: Double :: HNil]('*' :: true :: "foo" :: 2.0 :: HNil, r5) + + val (b2, r6) = sl.replaceType[Boolean]('*') + typed[Char](r6(1)) + assertTypedEquals[Boolean](true, b2) + assertTypedEquals[Int :: Char :: String :: Double :: HNil](1 :: '*' :: "foo" :: 2.0 :: HNil, r6) + + val (s2, r7) = sl.replaceType[String]('*') + typed[Char](r7(2)) + assertTypedEquals[String]("foo", s2) + assertTypedEquals[Int :: Boolean :: Char :: Double :: HNil](1 :: true :: '*' :: 2.0 :: HNil, r7) + + val (d2, r8) = sl.replaceType[Double]('*') + typed[Double](d2) + typed[Char](r8(3)) + assertEquals(2.0, d2, Double.MinPositiveValue) + assertTypedEquals[Int :: Boolean :: String :: Char :: HNil](1 :: true :: "foo" :: '*' :: HNil, r8) + + val fruits = a :: p :: a :: f :: HNil + val (x1, rr1) = fruits.replaceType[Pear](a) + typed[Pear](x1) + typed[Apple :: Apple :: Apple :: Fruit :: HNil](rr1) + + val (x2, rr2) = fruits.replaceType[Pear](f) + typed[Pear](x2) + typed[Apple :: Fruit :: Apple :: Fruit :: HNil](rr2) + + val (x3, rr3) = fruits.replaceType[Fruit](p) + typed[Fruit](x3) + typed[Apple :: Pear :: Apple :: Pear :: HNil](rr3) + + val (x4, rr4) = fruits.replace(p) + typed[Pear](x4) + typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr4) + + val (x5, rr5) = fruits.replace(f) + typed[Fruit](x5) + typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr5) + } + + @Test + def testUpdate: Unit = { + type SL = Int :: Boolean :: String :: Double :: HNil + val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil + + val r1 = sl.updatedElem(23) + assertTypedEquals[SL](23 :: true :: "foo" :: 2.0 :: HNil, r1) + + val r2 = sl.updatedElem(false) + assertTypedEquals[SL](1 :: false :: "foo" :: 2.0 :: HNil, r2) + + val r3 = sl.updatedElem("bar") + assertTypedEquals[SL](1 :: true :: "bar" :: 2.0 :: HNil, r3) + + val r4 = sl.updatedElem(3.0) + assertTypedEquals[SL](1 :: true :: "foo" :: 3.0 :: HNil, r4) + + val r5 = sl.updatedType[Int]('*') + assertTypedEquals[Char :: Boolean :: String :: Double :: HNil]('*' :: true :: "foo" :: 2.0 :: HNil, r5) + + val r6 = sl.updatedType[Boolean]('*') + assertTypedEquals[Int :: Char :: String :: Double :: HNil](1 :: '*' :: "foo" :: 2.0 :: HNil, r6) + + val r7 = sl.updatedType[String]('*') + assertTypedEquals[Int :: Boolean :: Char :: Double :: HNil](1 :: true :: '*' :: 2.0 :: HNil, r7) + + val r8 = sl.updatedType[Double]('*') + assertTypedEquals(1 :: true :: "foo" :: '*' :: HNil, r8) + + val r9 = sl.updateWith((i : Int) => i * 2) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](2 :: true :: "foo" :: 2.0 :: HNil, r9) + + val r10 = sl.updateWith((b : Boolean) => !b) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: false :: "foo" :: 2.0 :: HNil, r10) + + val r11 = sl.updateWith((s : String) => s.toUpperCase) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "FOO" :: 2.0 :: HNil, r11) + + val r12 = sl.updateWith((d : Double) => d / 2.0) + assertTypedEquals[Int :: Boolean :: String :: Double :: HNil](1 :: true :: "foo" :: 1.0 :: HNil, r12) + + val r13 = sl.updateWith((i : Int) => i.toString) + assertTypedEquals[String :: Boolean :: String :: Double :: HNil]("1" :: true :: "foo" :: 2.0 :: HNil, r13) + + val r14 = sl.updateWith((b : Boolean) => b.toString) + assertTypedEquals[Int :: String :: String :: Double :: HNil](1 :: "true" :: "foo" :: 2.0 :: HNil, r14) + + val r15 = sl.updateWith((_ : String) => 0xF00) + assertTypedEquals[Int :: Boolean :: Int :: Double :: HNil](1 :: true :: 0xF00 :: 2.0 :: HNil, r15) + + val r16 = sl.updateWith((d : Double) => d.toString) + assertTypedEquals[Int :: Boolean :: String :: String :: HNil](1 :: true :: "foo" :: 2.0.toString :: HNil, r16) + + val fruits = a :: p :: a :: f :: HNil + + val rr1 = fruits.updatedType[Pear](a) + typed[Apple :: Apple :: Apple :: Fruit :: HNil](rr1) + + val rr2 = fruits.updatedType[Pear](f) + typed[Apple :: Fruit :: Apple :: Fruit :: HNil](rr2) + + val rr3 = fruits.updatedType[Fruit](p) + typed[Apple :: Pear :: Apple :: Pear :: HNil](rr3) + + val rr4 = fruits.updatedElem(p) + typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr4) + + val rr5 = fruits.updatedElem(f) + typed[Apple :: Pear :: Apple :: Fruit :: HNil](rr5) + } + + @Test + def testSplitLeft: Unit = { + type SL = Int :: Boolean :: String :: Double :: HNil + type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil + val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil + val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val (sp1, sp2) = sl.splitLeft[String] + typed[String :: Double :: HNil](sp2) + typed[Int :: Boolean :: HNil](sp1) + assertTypedEquals[SL]((sp1 ::: sp2), sl) + + val (sli1, sli2) = sl2.splitLeft[String] + typed[Int :: Double :: HNil](sli1) + typed[String :: Unit :: String :: Boolean :: Long :: HNil](sli2) + assertTypedEquals[SL2]((sli1 ::: sli2), sl2) + + val (rsp1, rsp2) = sl.reverse_splitLeft[String] + typed[Boolean :: Int :: HNil](rsp1) + typed[String :: Double :: HNil](rsp2) + assertTypedEquals[SL]((rsp1 reverse_::: rsp2), sl) + + val (rsli1, rsli2) = sl2.reverse_splitLeft[String] + typed[Double :: Int :: HNil](rsli1) + typed[String :: Unit :: String :: Boolean :: Long :: HNil](rsli2) + assertTypedEquals[SL2]((rsli1 reverse_::: rsli2), sl2) + } + + @Test + def testSplitLeftP: Unit = { + type SL = Int :: Boolean :: String :: Double :: HNil + type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil + val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil + val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val sp1 :: sp2 :: HNil = sl.splitLeftP[String] : @unchecked + typed[String :: Double :: HNil](sp2) + typed[Int :: Boolean :: HNil](sp1) + assertTypedEquals[SL]((sp1 ::: sp2), sl) + + val sli1 :: sli2 :: HNil = sl2.splitLeftP[String] : @unchecked + typed[Int :: Double :: HNil](sli1) + typed[String :: Unit :: String :: Boolean :: Long :: HNil](sli2) + assertTypedEquals[SL2]((sli1 ::: sli2), sl2) + + val rsp1 :: rsp2 :: HNil = sl.reverse_splitLeftP[String] : @unchecked + typed[Boolean :: Int :: HNil](rsp1) + typed[String :: Double :: HNil](rsp2) + assertTypedEquals[SL]((rsp1 reverse_::: rsp2), sl) + + val rsli1 :: rsli2 :: HNil = sl2.reverse_splitLeftP[String] : @unchecked + typed[Double :: Int :: HNil](rsli1) + typed[String :: Unit :: String :: Boolean :: Long :: HNil](rsli2) + assertTypedEquals[SL2]((rsli1 reverse_::: rsli2), sl2) + } + + @Test + def testSplitRight: Unit = { + type SL = Int :: Boolean :: String :: Double :: HNil + type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil + val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil + val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val (srp1, srp2) = sl.splitRight[String] + typed[Int :: Boolean :: String :: HNil](srp1) + typed[Double :: HNil](srp2) + assertTypedEquals[SL]((srp1 ::: srp2), sl) + + val (srli1, srli2) = sl2.splitRight[String] + typed[Int :: Double :: String :: Unit :: String :: HNil](srli1) + typed[Boolean :: Long :: HNil](srli2) + assertTypedEquals[SL2](sl2, srli1 ::: srli2) + + val (rsrp1, rsrp2) = sl.reverse_splitRight[String] + typed[String :: Boolean :: Int :: HNil](rsrp1) + typed[Double :: HNil](rsrp2) + assertTypedEquals[SL]((rsrp1 reverse_::: rsrp2), sl) + + val (rsrli1, rsrli2) = sl2.reverse_splitRight[String] + typed[String :: Unit :: String :: Double :: Int :: HNil](rsrli1) + typed[Boolean :: Long :: HNil](rsrli2) + assertTypedEquals[SL2]((rsrli1 reverse_::: rsrli2), sl2) + } + + @Test + def testSplitRightP: Unit = { + type SL = Int :: Boolean :: String :: Double :: HNil + type SL2 = Int :: Double :: String :: Unit :: String :: Boolean :: Long :: HNil + val sl: SL = 1 :: true :: "foo" :: 2.0 :: HNil + val sl2: SL2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val srp1 :: srp2 :: HNil = sl.splitRightP[String] : @unchecked + typed[Int :: Boolean :: String :: HNil](srp1) + typed[Double :: HNil](srp2) + assertTypedEquals[SL]((srp1 ::: srp2), sl) + + val srli1 :: srli2 :: HNil = sl2.splitRightP[String] : @unchecked + typed[Int :: Double :: String :: Unit :: String :: HNil](srli1) + typed[Boolean :: Long :: HNil](srli2) + assertTypedEquals[SL2](sl2, srli1 ::: srli2) + + val rsrp1 :: rsrp2 :: HNil = sl.reverse_splitRightP[String] : @unchecked + typed[String :: Boolean :: Int :: HNil](rsrp1) + typed[Double :: HNil](rsrp2) + assertTypedEquals[SL]((rsrp1 reverse_::: rsrp2), sl) + + val rsrli1 :: rsrli2 :: HNil = sl2.reverse_splitRightP[String] : @unchecked + typed[String :: Unit :: String :: Double :: Int :: HNil](rsrli1) + typed[Boolean :: Long :: HNil](rsrli2) + assertTypedEquals[SL2]((rsrli1 reverse_::: rsrli2), sl2) + } + + @Test + def testTranspose: Unit = { + val l1 = 1 :: HNil + val l2 = ("a" :: HNil) :: HNil + + val r1 = l1.zipOne(l2) + assertTypedEquals[(Int :: String :: HNil) :: HNil]((1 :: "a" :: HNil) :: HNil, r1) + val r2 = l1.mapConst(HNil) + assertTypedEquals[HNil :: HNil](HNil :: HNil, r2) + val r3 = (l1 :: HNil).transpose + assertTypedEquals[(Int :: HNil) :: HNil]((1 :: HNil) :: HNil, r3) + + val l3 = 1 :: 2 :: 3 :: HNil + val l4 = ("a" :: 1.0 :: HNil) :: ("b" :: 2.0 :: HNil) :: ("c" :: 3.0 :: HNil) :: HNil + + type ISD = Int :: String :: Double :: HNil + val z2 = l3.zipOne(l4) + assertTypedEquals[ISD :: ISD :: ISD :: HNil]( + (1 :: "a" :: 1.0 :: HNil) :: (2 :: "b" :: 2.0 :: HNil) :: (3 :: "c" :: 3.0 :: HNil) :: HNil, z2 + ) + + val r5 = l3.mapConst(HNil) + assertTypedEquals[HNil :: HNil :: HNil :: HNil](HNil :: HNil :: HNil :: HNil, r5) + + val t2 = l4.transpose + assertTypedEquals[ + (String :: String :: String :: HNil) :: + (Double :: Double :: Double :: HNil) :: HNil + ](("a" :: "b" :: "c" :: HNil) :: (1.0 :: 2.0 :: 3.0 :: HNil) :: HNil, t2) + + val t3 = z2.transpose + assertTypedEquals[ + (Int :: Int :: Int :: HNil) :: + (String :: String :: String :: HNil) :: + (Double :: Double :: Double :: HNil) :: HNil + ]( + (1 :: 2 :: 3 :: HNil) :: + ("a" :: "b" :: "c" :: HNil) :: + (1.0 :: 2.0 :: 3.0 :: HNil) :: HNil, + t3 + ) + + val r8 = t3.transpose + assertTypedEquals[ISD :: ISD :: ISD :: HNil](z2, r8) + + val nil: HNil = HNil + + val r9 = nil zipOne nil + assertTypedEquals[HNil](HNil, r9) + + val r10 = nil.transpose + assertTypedEquals[HNil](HNil, r10) + + val r11 = (HNil :: HNil :: HNil : HNil :: HNil :: HNil).transpose + assertTypedEquals[HNil](HNil, r11) + + val r12 = (1 :: HNil) zipOne ((2 :: HNil) :: HNil) + assertTypedEquals[(Int :: Int :: HNil) :: HNil]((1 :: 2 :: HNil) :: HNil, r12) + } + + @Test + def testZipUnzip: Unit = { + val l1 = 1 :: "a" :: 1.0 :: HNil + val l2 = 2 :: "b" :: 2.0 :: HNil + + val t1 = (l1 :: l2 :: HNil).transpose + val z1 = t1.map(tupled) + assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( + (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z1) + + def zip[L <: HList, OutT <: HList](l : L) + (implicit + transposer : Transposer.Aux[L, OutT], + mapper : Mapper[tupled.type, OutT]) = l.transpose.map(tupled) + + val z2 = zip(l1 :: l2 :: HNil) + assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( + (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z2) + + val z3 = (l1 :: l2 :: HNil).zip + assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( + (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, z3) + + val nil : HNil = HNil + val z4 = (nil :: nil :: HNil).zip + assertTypedEquals[HNil](nil, z4) + + val t2 = z1.map(productElements).transpose + val u1 = t2.tupled + assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( + (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), u1) + + def unzip[L <: HList, OutM <: HList, OutT <: HList](l : L) + (implicit + mapper : Mapper.Aux[productElements.type, L, OutM], + transposer : Transposer.Aux[OutM, OutT], + tupler : Tupler[OutT]) = l.map(productElements).transpose.tupled + + val u2 = unzip(z1) + assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( + (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), u2) + + val r1 = z1.unzip + assertTypedEquals[(Int :: String :: Double :: HNil, Int :: String :: Double :: HNil)]( + (1 :: "a" :: 1.0 :: HNil, 2 :: "b" :: 2.0 :: HNil), r1) + + val r2 = l1 zip l2 + assertTypedEquals[(Int, Int) :: (String, String) :: (Double, Double) :: HNil]( + (1, 2) :: ("a", "b") :: (1.0, 2.0) :: HNil, r2) + + val intInc : Int => Int = _+1 + val stringInc : String => String = _+"*" + val doubleInc : Double => Int = _.toInt+1 + + val l3 = intInc :: stringInc :: doubleInc :: HNil + + val z5 = l3 zipApply l1 + assertTypedEquals[Int :: String :: Int :: HNil](2 :: "a*" :: 2 :: HNil, z5) + } + + @Test + def testUnapply: Unit = { + val l = 1 :: true :: "foo" :: 2.0 :: HNil + val l2 = 23 :: 3.0 :: "foo" :: () :: "bar" :: true :: 5L :: HNil + + val is = l match { + case i :: true :: s :: 2.0 :: HNil => (i, s) + case _ => sys.error("Not matched") + } + + assertTypedEquals[Int](1, is._1) + assertTypedEquals[String]("foo", is._2) + + val is2 = (l : Any) match { + case (i : Int) :: true :: (s : String) :: 2.0 :: HNil => (i, s) + case _ => sys.error("Not matched") + } + + assertTypedEquals[Int](1, is2._1) + assertTypedEquals[String]("foo", is2._2) + + import HList.ListCompat._ + + val tl = l2 match { + case 23 #: 3.0 #: s #: xs => (s, xs) + case _ => sys.error("Not matched") + } + + assertTypedEquals[String]("foo", tl._1) + assertTypedEquals[Unit :: String :: Boolean :: Long :: HNil](() :: "bar" :: true :: 5L :: HNil, tl._2) + + val tl2 = (l2 : Any) match { + case 23 #: 3.0 #: (s : String) #: xs => (s, xs) + case _ => sys.error("Not matched") + } + + assertTypedEquals[String]("foo", tl2._1) + assertTypedEquals[HList](() :: "bar" :: true :: 5L :: HNil, tl2._2) + + val ll = List(1, 2, 3, 4) + val tll = ll match { + case 1 :: 2 :: x :: y :: Nil => (x, y) + case _ => sys.error("Not matched") + } + assertTypedEquals[Int](3, tll._1) + assertTypedEquals[Int](4, tll._2) + + val tll2 = ll match { + case 1 :: xs => xs + case _ => sys.error("Not matched") + } + assertTypedEquals[List[Int]](List(2, 3, 4), tll2) + + val mixed = 23 :: "foo" :: (1 :: 2 :: 3 :: 4 :: 5 :: Nil) :: false :: () :: HNil + val tmixed = mixed match { + case _ #: _ #: (_ :: 2 :: x :: tl1) #: tl2 => (x, tl1, tl2) + case _ => sys.error("Not matched") + } + assertTypedEquals[Int](3, tmixed._1) + assertTypedEquals[List[Int]](4 :: 5 :: Nil, tmixed._2) + assertTypedEquals[Boolean :: Unit :: HNil](false :: () :: HNil, tmixed._3) + } + + @Test + def testRemove: Unit = { + val l = 1 :: true :: "foo" :: HNil + + val li = l.removeElem[Int] + assertTypedEquals[(Int, Boolean :: String :: HNil)]((1, true :: "foo" :: HNil), li) + + val lb = l.removeElem[Boolean] + assertTypedEquals[(Boolean, Int :: String :: HNil)]((true, 1 :: "foo" :: HNil), lb) + + val ls = l.removeElem[String] + assertTypedEquals[(String, Int :: Boolean :: HNil)](("foo", 1 :: true :: HNil), ls) + + val withDuplicates = 1 :: 'a' :: 'b' :: HNil + val remover = implicitly[Remove.Aux[Int :: Char :: Char :: HNil, Char, (Char, Int :: Char :: HNil)]] + assertTypedEquals[(Char, Int :: Char :: HNil)](('a', 1 :: 'b' :: HNil), remover(withDuplicates)) + } + + @Test + def testRemoveAll: Unit = { + val l = 1 :: true :: "foo" :: HNil + + val lnil = l.removeAll[HNil] + assertTypedEquals[(HNil, Int :: Boolean :: String :: HNil)]((HNil, 1 :: true :: "foo" :: HNil), lnil) + + val li = l.removeAll[Int :: HNil] + assertTypedEquals[(Int :: HNil, Boolean :: String :: HNil)]((1 :: HNil, true :: "foo" :: HNil), li) + + val lb = l.removeAll[Boolean :: HNil] + assertTypedEquals[(Boolean :: HNil, Int :: String :: HNil)]((true :: HNil, 1 :: "foo" :: HNil), lb) + + val lbi = l.removeAll[Boolean :: Int :: HNil] + assertTypedEquals[(Boolean :: Int :: HNil, String :: HNil)]((true :: 1 :: HNil, "foo" :: HNil), lbi) + } + + @Test + def testUnion: Unit = { + type L1 = String :: Long :: HNil + val l1: L1 = "foo" :: 3L :: HNil + + type L2 = Int :: String :: Boolean :: HNil + val l2: L2 = 2 :: "bar" :: true :: HNil + + type L3 = Int :: Int :: HNil + val l3: L3 = 1 :: 2 :: HNil + + type L4 = Int :: Int :: Int :: HNil + val l4: L4 = 4 :: 5 :: 6 :: HNil + + val lnil = l1.union[HNil](HNil) + assertTypedEquals[L1](l1, lnil) + + val lself = l1.union(l1) + assertTypedEquals[L1](l1, lself) + + val l12 = l1.union(l2) + assertTypedEquals[String :: Long :: Int :: Boolean :: HNil]("foo" :: 3L :: 2 :: true :: HNil, l12) + + val l21 = l2.union(l1) + assertTypedEquals[Int :: String :: Boolean :: Long :: HNil](2 :: "bar" :: true :: 3L :: HNil, l21) + + + illTyped { """implicitly[Union.Aux[Int :: HNil, Int :: HNil, Int :: Int :: HNil]]"""} + + val ldup1 = (l3).union(l4) + assertTypedEquals[Int :: Int :: Int :: HNil](1 :: 2 :: 6 :: HNil, ldup1) + + val ldup2 = (l4).union(l3) + assertTypedEquals[Int :: Int :: Int :: HNil](4 :: 5 :: 6 :: HNil, ldup2) + } + + @Test + def testIntersection: Unit = { + type L1 = String :: Long :: Int :: HNil + val l1: L1 = "foo" :: 1L :: 3 :: HNil + + type L2 = Int :: String :: Boolean :: HNil + val l2: L2 = 2 :: "bar" :: true :: HNil + + type L3 = Int :: String :: Int :: HNil + val l3: L3 = 4 :: "foo" :: 5 :: HNil + + val lnil = l1.intersect[HNil] + assertTypedEquals[HNil](HNil, lnil) + + val lself = l1.intersect[L1] + assertTypedEquals[L1](l1, lself) + + val l12 = l1.intersect[L2] + assertTypedEquals[String :: Int :: HNil]("foo" :: 3 :: HNil, l12) + + val l21 = l2.intersect[L1] + assertTypedEquals[Int :: String :: HNil](2 :: "bar" :: HNil, l21) + + illTyped { """implicitly[Intersection.Aux[Int :: HNil, Int :: HNil, HNil]]"""} + + val ldup1 = (l3).intersect[Int :: HNil] + assertTypedEquals[Int :: HNil](4 :: HNil, ldup1) + + val ldup2 = (l3).intersect[Int :: Int :: HNil] + assertTypedEquals[Int :: Int :: HNil](4 :: 5 :: HNil, ldup2) + + val ldup3 = (l3).intersect[String :: HNil] + assertTypedEquals[String :: HNil]("foo" :: HNil, ldup3) + } + + @Test + def testDiff: Unit = { + type L1 = String :: Long :: Int :: HNil + val l1: L1 = "foo" :: 1L :: 3 :: HNil + + type L2 = Int :: String :: Boolean :: HNil + val l2: L2 = 2 :: "bar" :: true :: HNil + + type L3 = Int :: Boolean :: Int :: HNil + val l3: L3 = 4 :: false :: 5 :: HNil + + val lnil = l1.diff[HNil] + assertTypedEquals[L1](l1, lnil) + + val lself = l1.diff[L1] + assertTypedEquals[HNil](HNil, lself) + + val l12 = l1.diff[L2] + assertTypedEquals[Long :: HNil](1L :: HNil, l12) + + val l21 = l2.diff[L1] + assertTypedEquals[Boolean :: HNil](true :: HNil, l21) + + val ldup1 = (l3).diff[Int :: HNil] + assertTypedEquals[Boolean :: Int :: HNil](false :: 5 :: HNil, ldup1) + + val ldup2 = (l3).diff[Int :: Int :: HNil] + assertTypedEquals[Boolean :: HNil](false :: HNil, ldup2) + + val ldup3 = (l3).diff[Boolean :: HNil] + assertTypedEquals[Int :: Int :: HNil](4 :: 5 :: HNil, ldup3) + } + + @Test + def testReinsert: Unit = { + type L = Int :: Boolean :: String :: HNil + + val l: L = 1 :: true :: "foo" :: HNil + + val (i, li) = l.removeElem[Int] + assertTypedEquals[L](li.reinsert[L](i), l) + + val (b, lb) = l.removeElem[Boolean] + assertTypedEquals[L](lb.reinsert[L](b), l) + + val (s, ls) = l.removeElem[String] + assertTypedEquals[L](ls.reinsert[L](s), l) + } + + @Test + def testReinsertAll: Unit = { + type L = Int :: Boolean :: String :: HNil + + val l = 1 :: true :: "foo" :: HNil + + val (nil, lnil) = l.removeAll[HNil] + assertTypedEquals[L](lnil.reinsertAll[L](nil), l) + + val (i, li) = l.removeAll[Int :: HNil] + assertTypedEquals[L](li.reinsertAll[L](i), l) + + val (b, lb) = l.removeAll[Boolean :: HNil] + assertTypedEquals[L](lb.reinsertAll[L](b), l) + + val (bi, lbi) = l.removeAll[Boolean :: Int :: HNil] + assertTypedEquals[L](lbi.reinsertAll[L](bi), l) + } + + object combine extends Poly { + implicit def caseCharString: ProductCase.Aux[Char :: String :: HNil, Int] = use((c : Char, s : String) => s.indexOf(c)) + implicit def caseIntBoolean: ProductCase.Aux[Int :: Boolean :: HNil, String] = use((i : Int, b : Boolean) => if ((i >= 0) == b) "pass" else "fail") + } + + object toMapL extends Poly2 { + implicit def wrapMap[T]: Case.Aux[T, Int, Map[List[Int], T]] = + at[T, Int]((end, t) => Map(List(t) -> end)) + } + + @Test + def testFoldLeft: Unit = { + val c1a = combine('o', "foo") + val c1b = combine(c1a, true) + assertTypedEquals[String]("pass", c1b) + + implicitly[LeftFolder.Aux[HNil, String, combine.type, String]] + implicitly[LeftFolder.Aux[Boolean :: HNil, Int, combine.type, String]] + implicitly[LeftFolder.Aux[String :: Boolean :: HNil, Char, combine.type, String]] + + val tf1 = implicitly[LeftFolder[HNil, String, combine.type]] + val tf2 = implicitly[LeftFolder[Boolean :: HNil, Int, combine.type]] + val tf3 = implicitly[LeftFolder[String :: Boolean :: HNil, Char, combine.type]] + + val l1 = "foo" :: true :: HNil + val f1 = l1.foldLeft('o')(combine) + assertTypedEquals[String]("pass", f1) + + val c2a = combine('o', "bar") + val c2b = combine(c2a, false) + assertTypedEquals[String]("pass", c2b) + + val l2 = "bar" :: false :: HNil + val f2 = l2.foldLeft('o')(combine) + assertTypedEquals[String]("pass", f2) + + val l3 = 1 :: 2 :: HNil + val f3 = l3.foldLeft(0)(toMapL) + assertTypedEquals[Map[List[Int], Map[List[Int], Int]]](Map(List(2) -> Map(List(1) -> 0)), f3) + } + + object toMapR extends Poly2 { + implicit def wrapMap[T]: Case.Aux[Int, T, Map[List[Int], T]] = + at[Int, T]((t, end) => Map(List(t) -> end)) + } + + @Test + def testFoldRight: Unit = { + val l1 = 1 :: 2 :: HNil + val f1 = l1.foldRight(0)(toMapR) + assertTypedEquals[Map[List[Int], Map[List[Int], Int]]](Map(List(1) -> Map(List(2) -> 0)), f1) + } + + @Test + def testUpdatedAt: Unit = { + type IBS = Int :: Boolean :: String :: HNil + val l = 1 :: true :: "foo" :: HNil + + val r1 = l.updatedAt[_0](2) + assertTypedEquals[IBS](2 :: true :: "foo" :: HNil, r1) + + val r2 = l.updatedAt[_1](false) + assertTypedEquals[IBS](1 :: false :: "foo" :: HNil, r2) + + val r3 = l.updatedAt[_2]("bar") + assertTypedEquals[IBS](1 :: true :: "bar" :: HNil, r3) + } + + @Test + def testUpdatedAtLiteral: Unit = { + type IBS = Int :: Boolean :: String :: HNil + val l = 1 :: true :: "foo" :: HNil + + val r1 = l.updatedAt(0, 2) + assertTypedEquals[IBS](2 :: true :: "foo" :: HNil, r1) + + val r2 = l.updatedAt(1, false) + assertTypedEquals[IBS](1 :: false :: "foo" :: HNil, r2) + + val r3 = l.updatedAt(2, "bar") + assertTypedEquals[IBS](1 :: true :: "bar" :: HNil, r3) + } + + @Test + def testNatTRel: Unit = { + type L1 = Int :: String :: Boolean :: HNil + type L2 = List[Int] :: List[String] :: List[Boolean] :: HNil + type L3 = Option[Int] :: Option[String] :: Option[Boolean] :: HNil + type L4 = Int :: Int :: Int :: HNil + type L5 = String :: String :: String :: HNil + + implicitly[NatTRel[L1, Id, L2, List]] + implicitly[NatTRel[L2, List, L1, Id]] + + implicitly[NatTRel[L2, List, L3, Option]] + + implicitly[NatTRel[L1, Id, L4, Const[Int]#λ]] + + implicitly[NatTRel[L2, List, L4, Const[Int]#λ]] + } + + object optionToList extends (Option ~> List) { + def apply[A](fa: Option[A]): List[A] = List.fill(3)(fa.toList).flatten + } + + @Test + def testNatTRelMap: Unit = { + type L1 = Option[Int] :: Option[Boolean] :: Option[String] :: Option[Nothing] :: HNil + type L2 = List[Int] :: List[Boolean] :: List[String] :: List[Nothing] :: HNil + val nattrel = implicitly[NatTRel[L1, Option, L2, List]] + + val l1: L1 = Option(1) :: Option(true) :: Option("three") :: None :: HNil + val l2 = nattrel.map(optionToList, l1) + + assertTypedEquals[L2](l2, + List(1, 1, 1) :: List(true, true, true) :: List("three", "three", "three") :: List() :: HNil) + } + + @Test + def testZipConst: Unit = { + type IBS = Int :: Boolean :: String :: HNil + val c = 5 + type WithConst = (Int, Int) :: (Boolean, Int) :: (String, Int) :: HNil + val l = 1 :: true :: "a" :: HNil + typed[IBS](l) + val expected = (1, c) :: (true, c) :: ("a", c) :: HNil + + val zcIntIbs = ZipConst[Int, IBS] + val zipped1 = zcIntIbs(c, l) + assertTypedEquals[WithConst](expected, zipped1) + + val zcaIntIbs = implicitly[ZipConst.Aux[Int, IBS, WithConst]] + assertTypedEquals[WithConst](expected, zcaIntIbs(c, l)) + + val x = l.zipConst(c) + assertTypedEquals[WithConst](expected, x) + + HList().zipConst("") + } + + @Test + def testZipWith: Unit = { + import poly._ + + object empty extends Poly2 + + object add extends Poly2 { + implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) + } + + // HNil zipWith HNil (emptyFn) + val r1 = (HNil: HNil).zipWith(HNil: HNil)(empty) + assertTypedEquals[HNil](HNil, r1) + + // HNil zipWith nonEmpty (emptyFn) + val r2 = (HNil: HNil).zipWith(1 :: HNil)(empty) + assertTypedEquals[HNil](HNil, r2) + + // nonEmpty zipWith HNil (emptyFn) + val r3 = (1 :: HNil).zipWith(HNil: HNil)(empty) + assertTypedEquals[HNil](HNil, r3) + + // singleton zipWith singleton + val r4 = (1 :: HNil).zipWith(2 :: HNil)(add) + assertTypedEquals[Int :: HNil](3 :: HNil, r4) + + { // longList zipWith longerList + type Left = Int :: String :: Double :: HNil + type Right = Int :: Double :: String :: Boolean :: HNil + + val left: Left = 1 :: "foo" :: 1.2 :: HNil + val right: Right = 2 :: 2.3 :: "3.4" :: true :: HNil + + object zipFn extends Poly2 { + implicit val caseIntInt: Case.Aux[Int, Int, Int] = at[Int, Int](_ + _) + implicit val caseStringDouble: Case.Aux[String, Double, String] = at[String, Double](_ + " -> " + _.toString) + implicit val caseDoubleString: Case.Aux[Double, String, Double] = at[Double, String](_ + _.toDouble) + } + + val r5 = left.zipWith(right)(zipFn) + assertTypedEquals[Int :: String :: Double :: HNil](3 :: "foo -> 2.3" :: 4.6 :: HNil, r5) + } + + def testZipWithIndex: Unit = { + + // HNil zipWithIndex + val r1 = (HNil: HNil).zipWithIndex + assertTypedEquals[HNil](HNil, r1) + + // One element HList zipWithIndex + val r2 = (0::HNil).zipWithIndex + assertTypedEquals[(Int,_0)::HNil]((0,_0)::HNil, r2) + + // HList zipWithIndex + val r3 = (0::1::2::3::HNil).zipWithIndex + assertTypedEquals[(Int,_0)::(Int,_1)::(Int,_2)::(Int,_3)::HNil]((0,_0)::(1,_1)::(2,_2)::(3,_3)::HNil, r3) + + } + + { // invalid polys + illTyped(""" + (1 :: HNil).zipWith(2 :: HNil)(empty) + """) + + object noIntFn extends Poly2 { + implicit val caseDoubleDouble: Case.Aux[Double, Double, Double] = at[Double, Double](_ + _) + } + + illTyped(""" + (1 :: HNil).zipWith(2 :: HNil)(noIntFn) + """) + + illTyped(""" + (1.0 :: 2 :: HNil).zipWith(2.0 :: 3 :: HNil)(noIntFn) + """) + } + } + + @Test + def testWithKeys: Unit = { + import record._ + import syntax.singleton._ + + val orig = + ("intField" ->> 1) :: + ("boolField" ->> true) :: + HNil + + val result = orig.values.zipWithKeys(orig.keys) + sameTyped(orig)(result) + assertEquals(orig, result) + val int = result.get("intField") + assertTypedEquals[Int](1, int) + val bool = result.get("boolField") + assertTypedEquals[Boolean](true, bool) + illTyped("""result.get("otherField")""") + + // key/value lengths must match up + illTyped("orig.tail.values.zipWithKeys(orig.keys)") + illTyped("orig.values.zipWithKeys(orig.keys.tail)") + + // Explicit type argument + { + val result = orig.values.zipWithKeys["intField" :: "boolField" :: HNil] + sameTyped(orig)(result) + assertEquals(orig, result) + val int = result.get("intField") + assertTypedEquals[Int](1, int) + val bool = result.get("boolField") + assertTypedEquals[Boolean](true, bool) + illTyped("""result.get("otherField")""") + + // key/value lengths must match up + illTyped(""" orig.tail.values.zipWithKeys["intField" :: "boolField" :: HNil] """) + illTyped(""" orig.values.zipWithKeys["boolField" :: HNil] """) + } + } + + @Test + def testCollect: Unit = { + import poly._ + + object empty extends Poly1 + + object complex extends Poly1 { + implicit val caseInt: Case.Aux[Int, Double] = at[Int](_.toDouble) + implicit val caseString: Case.Aux[String, Int] = at[String](_ => 1) + } + + val in: Int :: String :: Double :: HNil = 1 :: "foo" :: 2.2 :: HNil + + // HNil collect p + val r1 = (HNil: HNil).collect(empty) + assertTypedEquals[HNil](HNil, r1) + + val r2 = (HNil: HNil).collect(poly.identity) + assertTypedEquals[HNil](HNil, r2) + + val r3 = (HNil: HNil).collect(complex) + assertTypedEquals[HNil](HNil, r3) + + // non-HNil collect empty + val r4 = in.collect(empty) + assertTypedEquals[HNil](HNil, r4) + + // non-HNil collect identity + val r5 = in.collect(identity) + assertTypedEquals[Int :: String :: Double :: HNil](in, r5) + + // non-HNil collect complex + val r6 = in.collect(complex) + assertTypedEquals[Double :: Int :: HNil](1.0 :: 1 :: HNil, r6) + } + + @Test + def testOrdering: Unit = { + assertEquals(List(HNil: HNil, HNil), List(HNil: HNil, HNil).sorted) + + assertEquals(List(1 :: HNil, 2 :: HNil, 3 :: HNil), List(2 :: HNil, 1 :: HNil, 3 :: HNil).sorted) + + assertEquals( + List(1 :: "abc" :: HNil, 1 :: "def" :: HNil, 2 :: "abc" :: HNil, 2 :: "def" :: HNil), + List(2 :: "abc" :: HNil, 1 :: "def" :: HNil, 2 :: "def" :: HNil, 1 :: "abc" :: HNil).sorted + ) + } + + @Test + def testMapCons: Unit = { + type C = Char; type S = String; type I = Int; type D = Double + + val r1 = (HNil: HNil).mapCons('a') + assertTypedEquals[HNil](HNil, r1) + + val r2 = (HNil :: HNil).mapCons('a') + assertTypedEquals[(Char :: HNil) :: HNil]((('a' :: HNil) :: HNil), r2) + + val r3 = ((1 :: HNil) :: ("foo" :: HNil) :: (2.0 :: HNil) :: HNil).mapCons('a') + assertTypedEquals[(C::I::HNil) :: (C::S::HNil) :: (C::D::HNil) :: HNil]( + ('a' :: 1 :: HNil) :: ('a' :: "foo" :: HNil) :: ('a' :: 2.0 :: HNil) :: HNil, + r3 + ) + } + + @Test + def testInterleave: Unit = { + type C = Char; type S = String; type I = Int; type D = Double + def interleave[I, L <: HList](i: I, l: L)(implicit interleave: Interleave[I, L]): interleave.Out = interleave(i, l) + + val r1 = interleave('i', HNil) + assertTypedEquals[(Char :: HNil) :: HNil](('i' :: HNil) :: HNil, r1) + + val r2 = interleave('i', 1 :: HNil) + assertTypedEquals[(C::I::HNil) :: (I::C::HNil) :: HNil](('i' :: 1 :: HNil) :: (1 :: 'i' :: HNil) :: HNil, + r2 + ) + + val r3 = interleave('i', 1 :: "foo" :: HNil) + assertTypedEquals[(C::I::S::HNil) :: (I::C::S::HNil) :: (I::S::C::HNil) :: HNil]( + ('i' :: 1 :: "foo" :: HNil) :: + (1 :: 'i' :: "foo" :: HNil) :: + (1 :: "foo" :: 'i' :: HNil) :: HNil, + r3 + ) + + val r4 = interleave('i', 1 :: "foo" :: 2.0 :: HNil) + assertTypedEquals[(C::I::S::D::HNil) :: (I::C::S::D::HNil) :: (I::S::C::D::HNil) :: (I::S::D::C::HNil) :: HNil]( + ('i' :: 1 :: "foo" :: 2.0 :: HNil) :: + (1 :: 'i' :: "foo" :: 2.0 :: HNil) :: + (1 :: "foo" :: 'i' :: 2.0 :: HNil) :: + (1 :: "foo" :: 2.0 :: 'i' :: HNil) :: HNil, + r4 + ) + } + + @Test + def testFlatMapInterleave: Unit = { + type C = Char; type I = Int + + def flatMapInterleave[I, L <: HList](i: I, l: L)(implicit flatMapInterleave: FlatMapInterleave[I, L]) = + flatMapInterleave(i, l) + + val r1 = flatMapInterleave('i', HNil) + assertTypedEquals[HNil](HNil, r1) + + val r2 = flatMapInterleave('i', HNil :: HNil) + assertTypedEquals[(Char :: HNil) :: HNil](('i' :: HNil) :: HNil, r2) + + val r3 = flatMapInterleave('i', (1 :: HNil) :: (2 :: HNil) :: HNil) + assertTypedEquals[(C::I::HNil) :: (I::C::HNil) :: (C::I::HNil) :: (I::C::HNil) :: HNil]( + ('i' :: 1 :: HNil) :: + (1 :: 'i' :: HNil) :: + ('i' :: 2 :: HNil) :: + (2 :: 'i' :: HNil) :: HNil, + r3 + ) + } + + @Test + def testPermutations: Unit = { + type S = String; type I = Int; type D = Double + + val r1 = HNil.permutations + assertTypedEquals[HNil :: HNil](HNil :: HNil, r1) + + val r2 = (1 :: HNil).permutations + assertTypedEquals[(Int :: HNil) :: HNil]((1 :: HNil) :: HNil, r2) + + val r3 = (1 :: "foo" :: HNil).permutations + assertTypedEquals[(I::S::HNil) :: (S::I::HNil) :: HNil]( + (1 :: "foo" :: HNil) :: + ("foo" :: 1 :: HNil) :: HNil, + r3 + ) + + val r4 = (1 :: "foo" :: 2.0 :: HNil).permutations + assertTypedEquals[ + (I::S::D::HNil) :: (S::I::D::HNil) :: (S::D::I::HNil) :: + (I::D::S::HNil) :: (D::I::S::HNil) :: (D::S::I::HNil) :: HNil + ]( + (1 :: "foo" :: 2.0 :: HNil) :: + ("foo" :: 1 :: 2.0 :: HNil) :: + ("foo" :: 2.0 :: 1 :: HNil) :: + (1 :: 2.0 :: "foo" :: HNil) :: + (2.0 :: 1 :: "foo" :: HNil) :: + (2.0 :: "foo" :: 1 :: HNil) :: HNil, + r4 + ) + } + + @Test + def testMkString: Unit = { + assertEquals(s"⸨1, foo, ${2.0}⸩", (1 :: "foo" :: 2.0 :: HNil).mkString("⸨", ", ", "⸩")) + } + + @Test + def testRotateLeft: Unit = { + val in0 = HNil + val in1 = 1 :: HNil + val in2 = 1 :: "foo" :: HNil + val in3 = 1 :: "foo" :: 2.0 :: HNil + val in4 = 1 :: "foo" :: 2.0 :: 'a' :: HNil + type S = String; type I = Int; type D = Double; type C = Char + + { // rotateLeft(0) + val r1 = in0.rotateLeft(0) + assertTypedSame[HNil](HNil, r1) + val r2 = in1.rotateLeft(0) + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateLeft(0) + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in3.rotateLeft(0) + assertTypedSame[I :: S :: D :: HNil](in3, r4) + val r5 = in4.rotateLeft(0) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) + } + + { // rotateLeft[_0] + val r1 = in0.rotateLeft[_0] + assertTypedSame[HNil](HNil, r1) + val r2 = in1.rotateLeft[_0] + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateLeft[_0] + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in3.rotateLeft[_0] + assertTypedSame[I :: S :: D :: HNil](in3, r4) + val r5 = in4.rotateLeft[_0] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) + } + + { // rotateLeft(n % size == 0) + val r1 = in1.rotateLeft(1) + assertTypedSame[I :: HNil](in1, r1) + val r2 = in1.rotateLeft(2) + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateLeft(2) + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in2.rotateLeft(4) + assertTypedSame[I :: S :: HNil](in2, r4) + val r5 = in3.rotateLeft(3) + assertTypedSame[I :: S :: D :: HNil](in3, r5) + val r6 = in3.rotateLeft(6) + assertTypedSame[I :: S :: D :: HNil](in3, r6) + val r7 = in4.rotateLeft(4) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) + val r8 = in4.rotateLeft(8) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) + } + + { // rotateLeft[N % Size == 0] + val r1 = in1.rotateLeft[_1] + assertTypedSame[I :: HNil](in1, r1) + val r2 = in1.rotateLeft[_2] + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateLeft[_2] + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in2.rotateLeft[_4] + assertTypedSame[I :: S :: HNil](in2, r4) + val r5 = in3.rotateLeft[_3] + assertTypedSame[I :: S :: D :: HNil](in3, r5) + val r6 = in3.rotateLeft[_6] + assertTypedSame[I :: S :: D :: HNil](in3, r6) + val r7 = in4.rotateLeft[_4] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) + val r8 = in4.rotateLeft[_8] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) + } + + { // other(n) + val r1 = in2.rotateLeft(1) + assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) + + val r2 = in3.rotateLeft(1) + assertTypedEquals[S :: D :: I :: HNil]("foo" :: 2.0 :: 1 :: HNil, r2) + + val r3 = in4.rotateLeft(1) + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r3) + + val r4 = in4.rotateLeft(2) + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) + + val r5 = in4.rotateLeft(3) + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r5) + + val r6 = in4.rotateLeft(5) + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r6) + + val r7 = in4.rotateLeft(6) + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) + } + + { // other[N] + val r1 = in2.rotateLeft[_1] + assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) + + val r2 = in3.rotateLeft[_1] + assertTypedEquals[S :: D :: I :: HNil]("foo" :: 2.0 :: 1 :: HNil, r2) + + val r3 = in4.rotateLeft[_1] + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r3) + + val r4 = in4.rotateLeft[_2] + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) + + val r5 = in4.rotateLeft[_3] + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r5) + + val r6 = in4.rotateLeft[_5] + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r6) + + val r7 = in4.rotateLeft[_6] + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) + } + } + + @Test + def testRotateRight: Unit = { + val in0 = HNil + val in1 = 1 :: HNil + val in2 = 1 :: "foo" :: HNil + val in3 = 1 :: "foo" :: 2.0 :: HNil + val in4 = 1 :: "foo" :: 2.0 :: 'a' :: HNil + type S = String; type I = Int; type D = Double; type C = Char + + { // rotateRight(0) + val r1 = in0.rotateRight(0) + assertTypedSame[HNil](HNil, r1) + val r2 = in1.rotateRight(0) + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateRight(0) + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in3.rotateRight(0) + assertTypedSame[I :: S :: D :: HNil](in3, r4) + val r5 = in4.rotateRight(0) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) + } + + { // rotateRight[_0] + val r1 = in0.rotateRight[_0] + assertTypedSame[HNil](HNil, r1) + val r2 = in1.rotateRight[_0] + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateRight[_0] + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in3.rotateRight[_0] + assertTypedSame[I :: S :: D :: HNil](in3, r4) + val r5 = in4.rotateRight[_0] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r5) + } + + { // rotateRight(n % size == 0) + val r1 = in1.rotateRight(1) + assertTypedSame[I :: HNil](in1, r1) + val r2 = in1.rotateRight(2) + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateRight(2) + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in2.rotateRight(4) + assertTypedSame[I :: S :: HNil](in2, r4) + val r5 = in3.rotateRight(3) + assertTypedSame[I :: S :: D :: HNil](in3, r5) + val r6 = in3.rotateRight(6) + assertTypedSame[I :: S :: D :: HNil](in3, r6) + val r7 = in4.rotateRight(4) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) + val r8 = in4.rotateRight(8) + assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) + } + + { // rotateRight[N % Size == 0] + val r1 = in1.rotateRight[_1] + assertTypedSame[I :: HNil](in1, r1) + val r2 = in1.rotateRight[_2] + assertTypedSame[I :: HNil](in1, r2) + val r3 = in2.rotateRight[_2] + assertTypedSame[I :: S :: HNil](in2, r3) + val r4 = in2.rotateRight[_4] + assertTypedSame[I :: S :: HNil](in2, r4) + val r5 = in3.rotateRight[_3] + assertTypedSame[I :: S :: D :: HNil](in3, r5) + val r6 = in3.rotateRight[_6] + assertTypedSame[I :: S :: D :: HNil](in3, r6) + val r7 = in4.rotateRight[_4] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r7) + val r8 = in4.rotateRight[_8] + assertTypedSame[I :: S :: D :: C :: HNil](in4, r8) + } + + { // others(n) + val r1 = in2.rotateRight(1) + assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) + + val r2 = in3.rotateRight(1) + assertTypedEquals[D :: I :: S :: HNil](2.0 :: 1 :: "foo" :: HNil, r2) + + val r3 = in4.rotateRight(1) + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r3) + + val r4 = in4.rotateRight(2) + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) + + val r5 = in4.rotateRight(3) + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r5) + + val r6 = in4.rotateRight(5) + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r6) + + val r7 = in4.rotateRight(6) + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) + } + + { // others[N] + val r1 = in2.rotateRight[_1] + assertTypedEquals[S :: I :: HNil]("foo" :: 1 :: HNil, r1) + + val r2 = in3.rotateRight[_1] + assertTypedEquals[D :: I :: S :: HNil](2.0 :: 1 :: "foo" :: HNil, r2) + + val r3 = in4.rotateRight[_1] + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r3) + + val r4 = in4.rotateRight[_2] + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r4) + + val r5 = in4.rotateRight[_3] + assertTypedEquals[S :: D :: C :: I :: HNil]("foo" :: 2.0 :: 'a' :: 1 :: HNil, r5) + + val r6 = in4.rotateRight[_5] + assertTypedEquals[C :: I :: S :: D :: HNil]('a' :: 1 :: "foo" :: 2.0 :: HNil, r6) + + val r7 = in4.rotateRight[_6] + assertTypedEquals[D :: C :: I :: S :: HNil](2.0 :: 'a' :: 1 :: "foo" :: HNil, r7) + } + } + + object smear extends Poly { + implicit val caseIntInt: ProductCase.Aux[Int :: Int :: HNil, Int] = use((x: Int, y: Int) => x + y) + implicit val caseStringInt: ProductCase.Aux[String :: Int :: HNil, Int] = use((x: String, y: Int) => x.toInt + y) + implicit val caseIntString: ProductCase.Aux[Int :: String :: HNil, Int] = use((x: Int, y: String) => x + y.toInt) + } + + @Test + def testScanLeft: Unit = { + val in = 1 :: "2" :: HNil + val out = in.scanLeft(1)(smear) + + typed[Int :: Int :: Int :: HNil](out) + assertEquals(1 :: 2 :: 4 :: HNil, out) + } + + @Test + def testScanRight: Unit = { + val in = 1 :: "2" :: HNil + val out = in.scanRight(1)(smear) + + typed[Int :: Int :: Int :: HNil](out) + assertEquals(4 :: 3 :: 1 :: HNil, out) + } + + @Test + def testFill: Unit = { + { + val empty = HList.fill(0)(true) + typed[_0](empty.length) + } + + { + val empty = HList.fill[Boolean](0)(true) + typed[_0](empty.length) + } + + { + val single = HList.fill(1)(None) + typed[_1](single.length) + typed[None.type](single.head) + assertEquals(None, single.head) + } + + { + val single = HList.fill[None.type](1)(None) + typed[_1](single.length) + typed[None.type](single.head) + assertEquals(None, single.head) + } + + { + val three = HList.fill(3)(m2i) + typed[_3](three.length) + typed[M2[Int, Unit]](three(_0)) + typed[M2[Int, Unit]](three(_1)) + typed[M2[Int, Unit]](three(_2)) + assertEquals(m2i, three(_0)) + assertEquals(m2i, three(_1)) + assertEquals(m2i, three(_2)) + } + + { + val three = HList.fill[M2[Int, Unit]](3)(m2i) + typed[_3](three.length) + typed[M2[Int, Unit]](three(_0)) + typed[M2[Int, Unit]](three(_1)) + typed[M2[Int, Unit]](three(_2)) + assertEquals(m2i, three(_0)) + assertEquals(m2i, three(_1)) + assertEquals(m2i, three(_2)) + } + + { + val empty = HList.fill(0, 0)(true) + typed[_0](empty.length) + } + + { + val empty = HList.fill[Boolean](0, 0)(true) + typed[_0](empty.length) + } + + { + val empty = HList.fill(2, 0)(true) + typed[_2](empty.length) + typed[_0](empty(_0).length) + typed[_0](empty(_1).length) + } + + { + val empty = HList.fill[Boolean](2, 0)(true) + typed[_2](empty.length) + typed[_0](empty(_0).length) + typed[_0](empty(_1).length) + } + + { + val empty = HList.fill(0, 2)(true) + typed[_0](empty.length) + } + + { + val empty = HList.fill[Boolean](0, 2)(true) + typed[_0](empty.length) + } + + { + val oneByTwo = HList.fill(1, 2)(None) + typed[_1](oneByTwo.length) + typed[_2](oneByTwo.head.length) + typed[None.type](oneByTwo.head(_0)) + typed[None.type](oneByTwo.head(_1)) + assertEquals(None, oneByTwo.head(_0)) + assertEquals(None, oneByTwo.head(_1)) + } + + { + val oneByTwo = HList.fill[None.type](1, 2)(None) + typed[_1](oneByTwo.length) + typed[_2](oneByTwo.head.length) + typed[None.type](oneByTwo.head(_0)) + typed[None.type](oneByTwo.head(_1)) + assertEquals(None, oneByTwo.head(_0)) + assertEquals(None, oneByTwo.head(_1)) + } + + { + val twoByThree = HList.fill(2, 3)(None) + typed[_2](twoByThree.length) + typed[_3](twoByThree(_0).length) + typed[_3](twoByThree(_1).length) + typed[None.type](twoByThree.at[_0].at[_0]) + typed[None.type](twoByThree.at[_0].at[_1]) + typed[None.type](twoByThree.at[_0].at[_2]) + typed[None.type](twoByThree.at[_1].at[_0]) + typed[None.type](twoByThree.at[_1].at[_1]) + typed[None.type](twoByThree.at[_1].at[_2]) + assertEquals(None, twoByThree.at[_0].at[_0]) + assertEquals(None, twoByThree.at[_0].at[_1]) + assertEquals(None, twoByThree.at[_0].at[_2]) + assertEquals(None, twoByThree.at[_1].at[_0]) + assertEquals(None, twoByThree.at[_1].at[_1]) + assertEquals(None, twoByThree.at[_1].at[_2]) + } + + { + val twoByThree = HList.fill[None.type](2, 3)(None) + typed[_2](twoByThree.length) + typed[_3](twoByThree(_0).length) + typed[_3](twoByThree(_1).length) + typed[None.type](twoByThree.at[_0].at[_0]) + typed[None.type](twoByThree.at[_0].at[_1]) + typed[None.type](twoByThree.at[_0].at[_2]) + typed[None.type](twoByThree.at[_1].at[_0]) + typed[None.type](twoByThree.at[_1].at[_1]) + typed[None.type](twoByThree.at[_1].at[_2]) + assertEquals(None, twoByThree.at[_0].at[_0]) + assertEquals(None, twoByThree.at[_0].at[_1]) + assertEquals(None, twoByThree.at[_0].at[_2]) + assertEquals(None, twoByThree.at[_1].at[_0]) + assertEquals(None, twoByThree.at[_1].at[_1]) + assertEquals(None, twoByThree.at[_1].at[_2]) + } + } + + @Test + def testPolyFill = { + object zero extends Poly0 { + implicit val zeroInt: Case0[Int] = at[Int](0) + } + + implicit val emptyString: zero.Case0[String] = zero.at[String]("") + + val out = HList.fillWith[Int :: String :: Int :: HNil](zero) + assertEquals(out, 0 :: "" :: 0 :: HNil) + } + + @Test + def testPatch: Unit = { + val basehl = 1 :: 2 :: "three" :: HNil + + { //patch an empty hlist + val out = HNil.patch(0, basehl, 0) + val out2 = HNil.patch[_0,_0](basehl) + + typed[Int :: Int :: String :: HNil](out) + assertEquals(out, basehl) + assertTypedEquals[Int :: Int :: String :: HNil](out, out2) + } + + { //single patch w/ nothing removed + val out = basehl.patch(1, 4 :: HNil, 0) + val out2 = basehl.patch[_1,_0](4 :: HNil) + + typed[Int :: Int :: Int :: String :: HNil](out) + assertEquals(1 :: 4 :: 2 :: "three" :: HNil, out) + assertTypedEquals[Int :: Int :: Int :: String :: HNil](out, out2) + } + + { //single patch w/ 2 elements removed + val out = basehl.patch(1, 3 :: HNil, 2) + val out2 = basehl.patch[_1,_2](3 :: HNil) + + typed[Int :: Int :: HNil](out) + assertEquals(1 :: 3 :: HNil, out) + assertTypedEquals[Int :: Int :: HNil](out, out2) + } + + { //essentially append + val p = 4 :: 5 :: "six" :: HNil + val out = basehl.patch(3, p, 0) + val out2 = basehl.patch[_3,_0](p) + + typed[Int :: Int :: String :: Int :: Int :: String :: HNil](out) + assertEquals(1 :: 2 :: "three" :: 4 :: 5 :: "six" :: HNil, out) + assertTypedEquals[Int :: Int :: String :: Int :: Int :: String :: HNil](out, out2) + } + + { //several patched w/ everything from original removed + val sub = 4 :: "five" :: "six" :: HNil + val out = basehl.patch(0, sub, 3) + val out2 = basehl.patch[_0,_3](sub) + + typed[Int :: String :: String :: HNil](out) + assertEquals(sub, out) + assertTypedEquals[Int :: String :: String :: HNil](out, out2) + } + } + + @Test + def testToCoproduct: Unit = { + type PISB = Int :: String :: Boolean :: HNil + type CISBa = Int :+: String :+: Boolean :+: CNil + val toCoproduct = ToCoproduct[PISB] + type CISBb = toCoproduct.Out + implicitly[CISBa =:= CISBb] + } + + @Test + def testToSum: Unit = { + type PISB = Int :: String :: Boolean :: HNil + type CISBa = Int :+: String :+: Boolean :+: CNil + val toSum1 = ToSum[PISB] + type SISBa = toSum1.Out + implicitly[CISBa =:= SISBa] + + type PIISSB = Int :: Int :: String :: String :: Boolean :: HNil + val toSum2 = ToSum[PIISSB] + type SISBb = toSum2.Out + implicitly[CISBa =:= SISBb] + } + + @Test + def testHListTypeSelector: Unit = { + import syntax.singleton._ + + typed[HNil](HNil) + + typed[Int :: HNil](23 :: HNil) + + typed[Int :: String :: HNil](23 :: "foo" :: HNil) + + typed[Int :: String :: Boolean :: HNil](23 :: "foo" :: true :: HNil) + + // Literal types + + typed[2 :: HNil](2.narrow :: HNil) + + typed[2 :: "a" :: true :: HNil](2.narrow :: "a".narrow :: true.narrow :: HNil) + + illTyped(""" typed[2 :: HNil](3.narrow :: HNil) """) + + // Mix of standard and literal types + + typed[2 :: String :: true :: HNil](2.narrow :: "a" :: true.narrow :: HNil) + } + + @Test + def selectAllTest: Unit ={ + import shapeless._, record._ , ops.hlist.SelectAll + + //is there any way to do it without runtime overhead? + class TypeCaptured[T](val value: T) { + type _type = T + } + + def getFieldsByTypesOfSuper[Sub <: HList, Super <: HList](l: Sub)(implicit sa: SelectAll[Sub, Super]) = sa(l) + + val hsuper = new TypeCaptured("2":: true :: HNil) + val hsub = new TypeCaptured(1 :: "2":: true :: HNil) + + //testing with plain HList + assertTypedEquals[hsuper._type](hsuper.value, getFieldsByTypesOfSuper[hsub._type, hsuper._type](hsub.value)) + + val rsuper = new TypeCaptured(Record(b = true, c = "blah")) + val rsub = new TypeCaptured(Record(a = 1, b = true, c = "blah")) + + //testing with Record + assertTypedEquals[rsuper._type](rsuper.value, getFieldsByTypesOfSuper[rsub._type, rsuper._type](rsub.value)) + + } + + @Test + def testCollectFirst: Unit = { + object Foo extends Poly1{ + implicit def iinst: Case.Aux[Int, Int] = at[Int]{ _ + 1 } + } + val hlist1 = "foo" :: 2.0 :: 1 :: HNil + assertTypedEquals[Int](hlist1.collectFirst(Foo), 2) + + val hlist2 = "foo" :: 2.0 :: HNil + illTyped("""hlist2.collectFirst(Foo)""") + } + + @Test + def testGrouper: Unit = { + object toInt extends Poly1 { + implicit def default[N <: Nat](implicit toi: ops.nat.ToInt[N]): Case.Aux[N, Int] = at[N](_ => toi()) + } + def range[R <: HList](a: Nat, b: Nat)(implicit + range: ops.nat.Range.Aux[a.N, b.N, R], + mapper: ops.hlist.Mapper[toInt.type, R] + ) = mapper(range()) + + // group HNil + assertEquals(HNil: HNil, (HNil: HNil).group(2, 1)) + // group a HList of 4 items into 2 (4/2) tuples of 2 items + assertEquals( + (0, 1) ::(2, 3) :: HNil, + range(0, 4).group(2, 2) + ) + + // group a HList of 5 items into 2 (5/2) tuples of 2 items + // the last item does not make a complete partition and is dropped. + assertEquals( + (0, 1) ::(2, 3) :: HNil, + range(0, 5).group(2, 2) + ) + + // uses the step to select the starting point for each partition + assertEquals( + (0, 1) ::(4, 5) :: HNil, + range(0, 6).group(2, 4) + ) + + // if the step is smaller than the partition size, items will be reused + assertEquals( + (0, 1) ::(1, 2) ::(2, 3) :: HNil, + range(0, 4).group(2, 1) + ) + + // when there are not enough items to fill the last partition, a pad can be supplied. + assertEquals( + (0, 1) ::(2, 3) ::(4, 'a') :: HNil, + range(0, 5).group(2, 2, 'a' :: HNil) + ) + + // but only as many pad elements are used as necessary to fill the final partition. + assertEquals( + (0, 1) ::(2, 3) ::(4, 'a') :: HNil, + range(0, 5).group(2, 2, 'a' :: 'b' :: 'c' :: HNil) + ) + + } + + @Test + def testLiftAll: Unit = { + trait F[A] + implicit object FInt extends F[Int] + implicit object FString extends F[String] + + assertEquals(HNil, implicitly[LiftAll[F, HNil]].instances) + assertEquals(FInt :: HNil, implicitly[LiftAll[F, Int :: HNil]].instances) + assertEquals(FString :: FInt :: HNil, implicitly[LiftAll[F, String :: Int :: HNil]].instances) + illTyped("implicitly[LiftAll[F, Long :: String :: Int :: HNil]]") + + assertEquals(FInt :: HNil, LiftAll[F](1 :: HNil).instances) + } + + @Test + def testPadTo: Unit = { + val p1 = (1 :: "a" :: HNil).padTo(3, 0) + assertTypedEquals[Int :: String :: Int :: HNil](1 :: "a" :: 0 :: HNil, p1) + + val p2 = (1 :: "a" :: HNil).padTo(2, 0) + assertTypedEquals[Int :: String :: HNil](1 :: "a" :: HNil, p2) + + val p3 = (HNil: HNil).padTo(2, "a") + assertTypedEquals[String :: String :: HNil]("a" :: "a" :: HNil, p3) + + val p4 = (HNil: HNil).padTo(0, "a") + assertTypedEquals[HNil](HNil, p4) + + illTyped(""" (1 :: "a" :: HNil).padTo(1, 0) """) + } + + @Test + def testSlice: Unit = { + val r1 = (1 :: "a" :: 3 :: HNil).slice(0, 2) + assertTypedEquals[Int :: String :: HNil](1 :: "a" :: HNil, r1) + + val r2 = (1 :: "a" :: 3 :: HNil).slice(1, 2) + assertTypedEquals[String :: HNil]("a" :: HNil, r2) + + val r3 = (1 :: "a" :: 3 :: HNil).slice(2, 3) + assertTypedEquals[Int :: HNil](3 :: HNil, r3) + + val r4 = (HNil: HNil).slice(0, 0) + assertTypedEquals[HNil](HNil, r4) + + illTyped(""" (1 :: "a" :: 3 :: HNil).slice(0, 4) """) + illTyped(""" (1 :: "a" :: 3 :: HNil).slice(1, 0) """) + } + + @Test + def testToSizedHList: Unit = { + val ns = List(1,2,3,4) + assertTypedEquals[Option[III]](None, ns.toSizedHList(3)) + assertTypedEquals[Option[IIII]](Some(1 :: 2 :: 3 :: 4 :: HNil), ns.toSizedHList(4)) + } + + @Test + def testModifierAt: Unit = { + // first element + assertEquals((1, 42 :: 2 :: 3 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(0)(_ => 42)) + + //last element + assertEquals((3, 1 :: 2 :: 42 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(2)(_ => 42)) + + //different type + assertEquals((3, 1 :: 2 :: 42.0 :: HNil), (1 :: 2 :: 3 :: HNil).updateAtWith(2)(_ => 42.0)) + } + + @Test + def testReify: Unit = { + import syntax.singleton._ + + assertTypedEquals(HNil, Reify[HNil].apply()) + + assertTypedEquals("a".narrow :: HNil, Reify["a" :: HNil].apply()) + + assertTypedEquals("a".narrow :: 1.narrow :: "b".narrow :: true.narrow :: HNil, Reify["a" :: 1 :: "b" :: true :: HNil].apply()) + + illTyped("Reify[String :: Int :: HNil]") + illTyped("""Reify[String :: ("a" :: 1 :: "b" :: true :: HNil)]""") + } + + @Test + def testCombinations: Unit = { + type I = Int; type S = String + + val r1 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(2) + assertTypedEquals[ + (I :: S :: HNil) :: + (I :: I :: HNil) :: + (I :: I :: HNil) :: + (S :: I :: HNil) :: + (S :: I :: HNil) :: + (I :: I :: HNil) :: HNil + ]( + (1 :: "2" :: HNil) :: + (1 :: 3 :: HNil) :: + (1 :: 4 :: HNil) :: + ("2" :: 3 :: HNil) :: + ("2" :: 4 :: HNil) :: + (3 :: 4 :: HNil) :: HNil, r1) + + val r2 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(3) + assertTypedEquals[ + (I :: S :: I :: HNil) :: + (I :: S :: I :: HNil) :: + (I :: I :: I :: HNil) :: + (S :: I :: I :: HNil) :: HNil + ]( + (1 :: "2" :: 3 :: HNil) :: + (1 :: "2" :: 4 :: HNil) :: + (1 :: 3 :: 4 :: HNil) :: + ("2" :: 3 :: 4 :: HNil) :: HNil, r2) + + val r3 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(4) + assertTypedEquals[ + (I :: S :: I :: I :: HNil) :: HNil + ]( + (1 :: "2" :: 3 :: 4 :: HNil) :: HNil, r3) + + val r4 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(5) + assertTypedEquals[HNil](HNil, r4) + + val r5 = (1 :: "2" :: 3 :: 4 :: HNil).combinations(0) + assertTypedEquals[HNil :: HNil](HNil :: HNil, r5) + } + + @Test + def testIsHCons = assertTypedEquals[Int :: HNil](23 :: HNil, IsHCons[Int :: HNil].cons(23, HNil)) + + @Test + def testToProduct = { + val isbd = 2 :: "abc" :: true :: 3.0 :: HNil + val p = (2, ("abc", (true, (3.0, ())))) + + import syntax.std.tuple._ + assertEquals(isbd.toProduct, p) + assertEquals(p.toHList, isbd) + assertEquals(isbd.toProduct.toHList, isbd) + assertEquals(p.toHList.toProduct, p) + assertEquals((), (HNil: HNil).toProduct) + assertEquals(HNil, ().toHList) + } + + @Test + def testAuxImplicits: Unit = { + the[SplitRight.Aux[String :: Int :: Boolean :: HNil, Int, String :: Int :: HNil, Boolean :: HNil]] + the[Grouper.Aux[Int :: String :: Boolean :: HNil, _2, _1, (Int, String) :: (String, Boolean) :: HNil]] + the[PaddedGrouper.Aux[Int :: String :: Boolean :: HNil, _2, _2, Long :: HNil, (Int, String) :: (Boolean, Long) :: HNil]] + } +}