### Deriving Lens with MacroMirror.summonProduct Source: https://context7.com/kitlangton/quotidian/llms.txt This example shows how to create a Lens for a case class field using MacroMirror.summonProduct. It generates `get` and `set` methods for the lens based on the provided field selector. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* trait Lens[S, A]: def get(s: S): A def set(s: S, a: A): S object LensMacros: def makeLensImpl[S: Type, A: Type](selector: Expr[S => A])(using Quotes): Expr[Lens[S, A]] = import quotes.reflect.* selector.asTerm.underlyingArgument match case Lambda(_, select @ Select(_, _)) => val mirror = MacroMirror.summonProduct[S] val elem = mirror.elemForSymbol(select.symbol).get.asElemOf[A] '{ new Lens[S, A]: def get(s: S) = ${ elem.get('s) } def set(s: S, a: A) = ${ elem.set('s, 'a) } } case other => report.errorAndAbort(s"Expected s => s.field, got: ${other.show}") inline def make[S, A](inline selector: S => A): Lens[S, A] = ${ makeLensImpl('selector) } // Usage: case class Person(name: String, age: Int) val nameLens = LensMacros.make[Person, String](_.name) val p = Person("Alice", 40) println(nameLens.get(p)) // "Alice" println(nameLens.set(p, "Bob")) // Person("Bob", 40) ``` -------------------------------- ### MirrorElem - Accessing and Setting Individual Fields Source: https://context7.com/kitlangton/quotidian/llms.txt Use MirrorElem within macros to get and set individual fields of a product type. The `get` method retrieves the field's value as an Expr, and `set` produces a new instance with the field updated. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* case class Box(label: String, value: Int) // Inside a macro, use MirrorElem to access individual fields def showFieldsImpl[A: Type](expr: Expr[A])(using Quotes): Expr[String] = import quotes.reflect.* val mirror = MacroMirror.summonProduct[A] val parts: List[Expr[String]] = mirror.elems.map { elem => import elem.given val fieldValue = elem.get(expr) // Expr[fieldType] '{ ${ Expr(elem.label) } + "=" + ${ fieldValue.asExprOf[Any] }.toString } } parts.reduce((a, b) => '{ $a + ", " + $b }) // MirrorElem.set: produce an updated Expr[A] with a new field value def setLabelImpl(expr: Expr[Box], newLabel: Expr[String])(using Quotes): Expr[Box] = val mirror = MacroMirror.summonProduct[Box] val labelElem = mirror.elems.find(_.label == "label").get.asElemOf[String] labelElem.set(expr, newLabel) // Expr[Box] with label replaced inline def setBoxLabel(inline box: Box, inline lbl: String): Box = ${ setLabelImpl('box, 'lbl) } val b = setBoxLabel(Box("old", 10), "new") // b: Box("new", 10) ``` -------------------------------- ### Deriving Show Type Class with MacroMirror Source: https://context7.com/kitlangton/quotidian/llms.txt This example demonstrates deriving a Show type class for case classes, enums, and sealed traits using MacroMirror. It covers product types (case classes) and sum types (enums/sealed traits), utilizing MacroMirror.summon, MirrorElem.summon, and Expr.interpolatedString. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* trait Show[A]: def show(a: A): String object Show: extension [A: Show](a: A) def show: String = summon[Show[A]].show(a) given Show[Int] with { def show(a: Int) = a.toString } given Show[String] with { def show(a: String) = a } given [A: Show]: Show[Option[A]] with def show(a: Option[A]) = a.fold("None")("Some(" + _.show + ")") inline def derived[A]: Show[A] = ${ ShowMacro.deriveShow[A] } object ShowMacro: def deriveShow[A: Type](using Quotes): Expr[Show[A]] = import quotes.reflect.* MacroMirror.summon[A].getOrElse(report.errorAndAbort("Not a case class/enum/sealed trait")) match case m: MacroMirror.Product[?, ?] => deriveProduct[A](m) case m: MacroMirror.Sum[?, ?] => deriveSum[A](m) def deriveProduct[A: Type](using Quotes)(m: MacroMirror.Product[quotes.type, A]): Expr[Show[A]] = def makeStr(a: Expr[A]): Expr[String] = val parts: List[String | Expr[?]] = m.elems.flatMap { import elem.given val comma = if elem == m.elems.head then "" else ", " val tc = elem.summon[Show] List(s"$comma${elem.label} = ", '{ $tc.show(${ elem.get(a) }) }) } if m.monoType.isSingleton then Expr(m.label) else Expr.interpolatedString((s"${m.label}(" :: parts) :+ ")"*) '{ new Show[A] { def show(a: A) = ${ makeStr('a) } } } def deriveSum[A: Type](using Quotes)(m: MacroMirror.Sum[quotes.type, A]): Expr[Show[A]] = '{ val instances = ${ m.deriveArray[Show]([t] => () => deriveShow[t]) } new Show[A]: def show(a: A) = val ord = ${ m.mirrorExpr }.ordinal(a) instances(ord).asInstanceOf[Show[Any]].show(a) } // Usage: final case class Person(name: String, age: Int) derives Show final case class Pet(name: String, bones: Int, owner: Option[Person]) derives Show enum Color derives Show: case Red; case Green(name: String); case Blue val pet = Pet("Fido", 3, Some(Person("Alice", 40))) println(pet.show) // Pet(name = Fido, bones = 3, owner = Some(Person(name = Alice, age = 40))) val color: Color = Color.Green("Emerald") println(color.show) // Green(name = Emerald) ``` -------------------------------- ### Manual FromExpr and ToExpr Implementation (Before) Source: https://github.com/kitlangton/quotidian/blob/main/README.md Illustrates the verbose, manual implementation of `FromExpr` and `ToExpr` instances for case classes and enums, which quotidian aims to simplify. ```scala import quotidian.* import scala.quoted.* final case class Person(name: String, age: Int, pet: Pet) object Person: given FromExpr[Person] with def unapply(expr: Expr[Person])(using Quotes): Option[Person] = import quotes.reflect.* expr match case '{ Person(${ Expr(name) }, ${ Expr(age) }, ${ Expr(pet) }) } => Some(Person(name, age, pet)) case _ => None given ToExpr[Person] with def apply(person: Person)(using Quotes): Expr[Person] = import quotes.reflect.* '{ Person(${ Expr(person.name) }, ${ Expr(person.age) }, ${ Expr(person.pet) }) } final case class Pet(name: String, hasBone: Boolean, favoritePerson: Option[Person]) object Pet: given FromExpr[Pet] with def unapply(expr: Expr[Pet])(using Quotes): Option[Pet] = import quotes.reflect.* expr match case '{ Pet(${ Expr(name) }, ${ Expr(hasBone) }, ${ Expr(favoritePerson) }) } => Some(Pet(name, hasBone, favoritePerson)) case _ => None given ToExpr[Pet] with def apply(pet: Pet)(using Quotes): Expr[Pet] = import quotes.reflect.* '{ Pet(${ Expr(pet.name) }, ${ Expr(pet.hasBone) }, ${ Expr(pet.favoritePerson) }) } enum Fruit: case Apple(variety: String) case Orange(juiciness: Int) case Banana(isYellow: Boolean) object Fruit: given FromExpr[Fruit] with def unapply(expr: Expr[Fruit])(using Quotes): Option[Fruit] = import quotes.reflect.* expr match case '{ Fruit.Apple(${ Expr(variety) }) } => Some(Fruit.Apple(variety)) case '{ Fruit.Orange(${ Expr(juiciness) }) } => Some(Fruit.Orange(juiciness)) case '{ Fruit.Banana(${ Expr(isYellow) }) } => Some(Fruit.Banana(isYellow)) case _ => None given ToExpr[Fruit] with def apply(fruit: Fruit)(using Quotes): Expr[Fruit] = import quotes.reflect.* fruit match case Fruit.Apple(variety) => '{ Fruit.Apple(${ Expr(variety) }) } case Fruit.Orange(juiciness) => '{ Fruit.Orange(${ Expr(juiciness) }) } case Fruit.Banana(isYellow) => '{ Fruit.Banana(${ Expr(isYellow) }) } ``` -------------------------------- ### Build collections and strings with Expr extensions Source: https://context7.com/kitlangton/quotidian/llms.txt The quotidian.syntax._ import provides extension methods for Expr, simplifying the creation of common quoted collection and string types without manual boilerplate. ```scala import quotidian.syntax.* import scala.quoted.* def buildExamplesImpl(using Quotes): Expr[Unit] = // Expr.ofArray: produce Expr[Array[A]] from individual Expr[A] values val arrExpr: Expr[Array[String]] = Expr.ofArray(Expr("hello"), Expr("world")) // '{ Array("hello", "world") } // Expr.ofVector val vecExpr: Expr[Vector[Int]] = Expr.ofVector(Expr(1), Expr(2), Expr(3)) // '{ Vector(1, 2, 3) } // Expr.ofMap with string keys val mapExpr: Expr[Map[String, Int]] = Expr.ofMap(Seq("a" -> Expr(1), "b" -> Expr(2))) // '{ Map("a" -> 1, "b" -> 2) } // Expr.interpolatedString: build s"..." expressions from parts val nameExpr = Expr("Kit") val ageExpr = Expr(33) val strExpr: Expr[String] = Expr.interpolatedString("My name is ", nameExpr, " and I am ", ageExpr, " years old") // '{ s"My name is $name and I am $age years old" } '{ () } ``` -------------------------------- ### Add Quotidian to build.sbt Source: https://context7.com/kitlangton/quotidian/llms.txt Include the library in your project's build.sbt file to use its features. ```scala libraryDependencies += "io.github.kitlangton" %% "quotidian" % "0.0.14" ``` -------------------------------- ### Strictly summon product types with MacroMirror.summonProduct Source: https://context7.com/kitlangton/quotidian/llms.txt MacroMirror.summonProduct is used to obtain a MacroMirror.Product for case classes. It will fail compilation if the type is not a product type, making it suitable for macros operating on case classes. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* case class Config(host: String, port: Int) def printFieldsImpl[A: Type](using Quotes): Expr[Unit] = import quotes.reflect.* // Fails at compile time if A is not a product type val mirror = MacroMirror.summonProduct[A] mirror.elems.foreach { elem => println(s"Field: ${elem.label} : ${elem.typeRepr.show}") } '{ () } inline def printFields[A]: Unit = ${ printFieldsImpl[A] } printFields[Config] // Prints at compile time: // Field: host : String // Field: port : Int ``` -------------------------------- ### MacroMirror.Product - Copying Case Classes with Field Overrides Source: https://context7.com/kitlangton/quotidian/llms.txt Use MacroMirror.Product to copy a case class instance, overriding specific fields. This is useful for creating modified versions of existing objects within macros. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* case class Person(name: String, age: Int) // Macro that increments everyone's age def bumpAgeImpl[A: Type](expr: Expr[A])(using Quotes): Expr[A] = import quotes.reflect.* val mirror = MacroMirror.summonProduct[A] // copy() generates an Expr[A] with the named field overridden mirror.copy( expr, "age" -> '{ ${ mirror.elems.find(_.label == "age").get.get(expr).asExprOf[Int] } + 1 } ) inline def bumpAge[A](inline a: A): A = ${ bumpAgeImpl('a) } val older = bumpAge(Person("Alice", 41)) // older: Person("Alice", 42) ``` -------------------------------- ### MacroMirror.Product - Converting Case Classes to Array of Field Values Source: https://context7.com/kitlangton/quotidian/llms.txt Utilize MacroMirror.Product's toArrayExpr method to extract all field values from a case class instance into an Expr[Array[Any]]. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* case class Person(name: String, age: Int) // Macro that increments everyone's age def bumpAgeImpl[A: Type](expr: Expr[A])(using Quotes): Expr[A] = import quotes.reflect.* val mirror = MacroMirror.summonProduct[A] // copy() generates an Expr[A] with the named field overridden mirror.copy( expr, "age" -> '{ ${ mirror.elems.find(_.label == "age").get.get(expr).asExprOf[Int] } + 1 } ) inline def bumpAge[A](inline a: A): A = ${ bumpAgeImpl('a) } val older = bumpAge(Person("Alice", 41)) // older: Person("Alice", 42) // toArrayExpr: get all field values as Expr[Array[Any]] def toArrayImpl[A: Type](expr: Expr[A])(using Quotes): Expr[Array[Any]] = MacroMirror.summonProduct[A].toArrayExpr(expr) ``` -------------------------------- ### Derive FromExpr and ToExpr Instances (After) Source: https://github.com/kitlangton/quotidian/blob/main/README.md Use the `derives` keyword to automatically generate `FromExpr` and `ToExpr` instances for case classes and enums, significantly reducing boilerplate. ```scala import quotidian.* import scala.quoted.* case class Person(name: String, age: Int, pet: Pet) derives FromExpr, ToExpr case class Pet(name: String, hasBone: Boolean, favoritePerson: Option[Person]) derives FromExpr, ToExpr enum Fruit derives FromExpr, ToExpr: case Apple(variety: String) case Orange(juiciness: Int) case Banana(isYellow: Boolean) ``` -------------------------------- ### Derive Show instances for sealed traits with MacroMirror.Sum Source: https://context7.com/kitlangton/quotidian/llms.txt Use deriveArray to generate type class instances for all variants of a sealed trait. The deriveShowSumImpl function demonstrates this for the Show type class. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* sealed trait Shape case class Circle(radius: Double) extends Shape case class Rectangle(w: Double, h: Double) extends Shape // Derive an array of type class instances for every sum variant def deriveShowSumImpl[A: Type](using Quotes): Expr[Show[A]] = import quotes.reflect.* val mirror = MacroMirror.summon[A].get.asInstanceOf[MacroMirror.Sum[quotes.type, A]] '{ // deriveArray tries summonInline first, then falls back to the provided derivation val instances = ${ mirror.deriveArray[Show]([t] => () => ShowMacro.deriveShow[t]) } new Show[A]: def show(a: A): String = val m = ${ mirror.mirrorExpr } val ord = m.ordinal(a) instances(ord).asInstanceOf[Show[Any]].show(a) } ``` ```scala // ordinal: get the index of a specific variant's type def ordinalOf[A: Type](using Quotes)(variantName: String): Int = val mirror = MacroMirror.summon[A].get.asInstanceOf[MacroMirror.Sum[quotes.type, A]] // mirror.ordinal[Circle] — resolves at compile time mirror.elemLabels.indexOf(variantName) ``` -------------------------------- ### Add Quotidian Dependency Source: https://github.com/kitlangton/quotidian/blob/main/README.md Include this dependency in your Scala 3 project to use the quotidian library. ```scala "io.github.kitlangton" %% "quotidian" % "0.0.14" ``` -------------------------------- ### Term / Symbol Extensions Source: https://context7.com/kitlangton/quotidian/llms.txt The Term extensions expose a fluent `.call(...)` API for reflectively invoking methods on a `Term` at the AST level, abstracting over method overloads, type arguments, and multiple parameter lists. ```APIDOC ## `quotidian.syntax` — `Term` / `Symbol` Extensions The `Term` extensions expose a fluent `.call(...)` API for reflectively invoking methods on a `Term` at the AST level, abstracting over method overloads, type arguments, and multiple parameter lists. ```scala import quotidian.syntax.* import scala.quoted.* def termCallExamples(using Quotes): Unit = import quotes.reflect.* val instance: Term = '{ List(1, 2, 3) }.asTerm val methods = TypeRepr.of[List[Int]].typeSymbol.declaredMethods // .call(name): call a nullary method val sizeResult: Term = instance.call("size") // equivalent to Select.unique(instance, "size") // .call(name, args): call a method with value arguments (type args inferred) val headOptionResult: Term = instance.call("headOption") // .call(name, targs, args): call with explicit type arguments val mapSym = methods.find(_.name == "map").get val mapped: Term = instance.call( mapSym, List(TypeRepr.of[String]), List('{ (x: Int) => x.toString }.asTerm) ) // .selectUnique(name): low-level unique selection (like Select.unique) val headTerm: Term = instance.selectUnique("head") // Symbol.returnType: get the final return type of any symbol val addSym = TypeRepr.of[List[Int]].typeSymbol.declaredMethods.find(_.name == "size").get val retType: TypeRepr = addSym.returnType // TypeRepr.of[Int] // Symbol.paramTypes: flatten all param lists to a single list of TypeReprs val mapSym2 = methods.find(_.name == "map").get val paramTypes = mapSym2.paramTypes ``` ``` -------------------------------- ### Derive ToExpr for Case Classes Source: https://context7.com/kitlangton/quotidian/llms.txt Automatically generate ToExpr instances for case classes to convert runtime values into compile-time expressions. This is useful for lifting data into macros. ```scala import quotidian.* import scala.quoted.* case class Config(host: String, port: Int, debug: Boolean) derives ToExpr, FromExpr // Macro that lifts a Config value into an expression inline def makeConfig(inline cfg: Config): Config = ${ makeConfigImpl('cfg) } def makeConfigImpl(expr: Expr[Config])(using Quotes): Expr[Config] = // Extract the value via FromExpr, transform it, then lift back via ToExpr expr match case Expr(cfg) => val updated = cfg.copy(debug = true) Expr(updated) // ToExpr[Config] is invoked here case _ => expr val cfg = makeConfig(Config("localhost", 8080, false)) // cfg: Config("localhost", 8080, true) ``` -------------------------------- ### Refinement Extensions Source: https://context7.com/kitlangton/quotidian/llms.txt The `Refinement.of` extension method allows building structural refinement types from a list of `(String, TypeRepr)` pairs. ```APIDOC ## `quotidian.syntax` — `Refinement` Extensions The `Refinement.of` extension method allows building structural refinement types from a list of `(String, TypeRepr)` pairs. This is used by the example lens and accessor macro generators to produce precisely-typed selector objects. ```scala import quotidian.syntax.* import scala.quoted.* def buildRefinedType(using Quotes): quotes.reflect.TypeRepr = import quotes.reflect.* // Refinement.of[Base](name -> tpe, ...): layer multiple refinements at once val refined: TypeRepr = Refinement.of[Any]( Seq( "name" -> TypeRepr.of[String], "age" -> TypeRepr.of[Int] ) ) // equivalent to: Any { def name: String; def age: Int } // With an explicit base TypeRepr val refined2: TypeRepr = Refinement.of(TypeRepr.of[AnyRef], Seq("id" -> TypeRepr.of[Long])) refined ``` ``` -------------------------------- ### Summon MacroMirror for Type Inspection Source: https://context7.com/kitlangton/quotidian/llms.txt Summon a MacroMirror for a given type A within a macro. Handles product and sum types, reporting errors for unsupported types. ```scala import quotidian.* import quotidian.syntax.* import scala.quoted.* case class Point(x: Double, y: Double) // Summon a MacroMirror inside a macro def inspectImpl[A: Type](using Quotes): Expr[String] = import quotes.reflect.* MacroMirror.summon[A] match case Some(m: MacroMirror.Product[?, ?]) => val info = s"Product: ${m.label}, fields: ${m.elemLabels.mkString(", ")}" Expr(info) case Some(m: MacroMirror.Sum[?, ?]) => val info = s"Sum: ${m.label}, cases: ${m.elemLabels.mkString(", ")}" Expr(info) case None => report.errorAndAbort(s"No mirror for ${Type.show[A]}") inline def inspect[A]: String = ${ inspectImpl[A] } inspect[Point] // "Product: Point, fields: x, y" enum Color { case Red; case Green; case Blue } inspect[Color] // "Sum: Color, cases: Red, Green, Blue" ``` -------------------------------- ### Compile-time Debugging with Debug.debug Source: https://context7.com/kitlangton/quotidian/llms.txt Use Debug.debug and Debug.debugWithType to print expression details (printed form, AST, type metadata) during compilation and abort. Report.debug can be used to print any Tree within a macro implementation. ```scala import quotidian.* import scala.quoted.* // Debug.debug: prints EXPR / TERM / SymbolInfo at compile time, then aborts // Useful during macro development to inspect what is in scope inline def troubleshoot[A](inline expr: A): A = Debug.debug(expr) // compilation stops here with a detailed dump // Debug.debugWithType: also includes the full TypeRepr of the expression inline def troubleshootWithType[A](inline expr: A): A = Debug.debugWithType(expr) // Inside a macro, Report.debug prints any Tree def myMacroImpl[A: Type](expr: Expr[A])(using Quotes): Expr[A] = import quotes.reflect.* // Uncomment to dump the AST and abort: // Report.debug(expr.asTerm) expr ``` -------------------------------- ### Refinement Type Construction Source: https://context7.com/kitlangton/quotidian/llms.txt Build structural refinement types using `Refinement.of`. This allows layering multiple refinements onto a base type or creating refinements from scratch. ```scala import quotidian.syntax.* import scala.quoted.* def buildRefinedType(using Quotes): quotes.reflect.TypeRepr = import quotes.reflect.* // Refinement.of[Base](name -> tpe, ...): layer multiple refinements at once val refined: TypeRepr = Refinement.of[Any]( Seq( "name" -> TypeRepr.of[String], "age" -> TypeRepr.of[Int] ) ) // equivalent to: Any { def name: String; def age: Int } // With an explicit base TypeRepr val refined2: TypeRepr = Refinement.of(TypeRepr.of[AnyRef], Seq("id" -> TypeRepr.of[Long])) refined ``` -------------------------------- ### Term and Symbol Method Invocation Extensions Source: https://context7.com/kitlangton/quotidian/llms.txt Invoke methods reflectively on a `Term` using a fluent `.call(...)` API, abstracting over overloads and type arguments. Access symbol properties like return type and parameter types. ```scala import quotidian.syntax.* import scala.quoted.* def termCallExamples(using Quotes): Unit = import quotes.reflect.* val instance: Term = '{ List(1, 2, 3) }.asTerm val methods = TypeRepr.of[List[Int]].typeSymbol.declaredMethods // .call(name): call a nullary method val sizeResult: Term = instance.call("size") // equivalent to Select.unique(instance, "size") // .call(name, args): call a method with value arguments (type args inferred) val headOptionResult: Term = instance.call("headOption") // .call(name, targs, args): call with explicit type arguments val mapSym = methods.find(_.name == "map").get val mapped: Term = instance.call( mapSym, List(TypeRepr.of[String]), List('{ (x: Int) => x.toString }.asTerm) ) // .selectUnique(name): low-level unique selection (like Select.unique) val headTerm: Term = instance.selectUnique("head") // Symbol.returnType: get the final return type of any symbol val addSym = TypeRepr.of[List[Int]].typeSymbol.declaredMethods.find(_.name == "size").get val retType: TypeRepr = addSym.returnType // TypeRepr.of[Int] // Symbol.paramTypes: flatten all param lists to a single list of TypeReprs val mapSym2 = methods.find(_.name == "map").get val paramTypes = mapSym2.paramTypes ``` -------------------------------- ### TypeRepr Extensions Source: https://context7.com/kitlangton/quotidian/llms.txt Extensions on TypeRepr provide utilities for working with tuple-based type lists, companion references, field type introspection, and singleton unwrapping. ```APIDOC ## `quotidian.syntax` — `TypeRepr` Extensions Extensions on `TypeRepr` provide utilities for working with tuple-based type lists, companion references, field type introspection, and singleton unwrapping. ```scala import quotidian.syntax.* import scala.quoted.* def typeReprExamples(using Quotes): Unit = import quotes.reflect.* // tupleToList: convert a Tuple TypeRepr into a List[TypeRepr] val tupleType = TypeRepr.of[(Int, String, Boolean)] // Not directly a HKT tuple in reflect, but via Mirror: // TypeRepr.of[types].tupleToList → List(TypeRepr.of[Int], TypeRepr.of[String], ...) // TypeRepr.makeTuple: build a *: chain from a List[TypeRepr] val reconstructed = TypeRepr.makeTuple(List(TypeRepr.of[Int], TypeRepr.of[String])) // equivalent to TypeRepr.of[Int *: String *: EmptyTuple] // TypeRepr.makeTupleClass: build a TupleN type (Tuple2[Int, String]) val tupleClass = TypeRepr.makeTupleClass(List(TypeRepr.of[Int], TypeRepr.of[String])) // TypeRepr.companionOf / TypeRepr.companionClassOf val companionRef = TypeRepr.companionOf[Option[Int]] // Expr companion module val companionClassRef = TypeRepr.companionClassOf[Option[Int]] // TypeRepr.fieldTypes: list the field types of a product val fieldTypesOfPerson = TypeRepr.fieldTypes[case class Temp(x: Int, y: String)] // .unapplied: strip type arguments → Option[Int].unapplied == Option val baseOption = TypeRepr.of[Option[Int]].unapplied // .valueAs[A]: extract a literal constant value from a TypeRepr // Used internally for MirroredLabel extraction ``` ``` -------------------------------- ### TypeRepr Tuple and Field Utilities Source: https://context7.com/kitlangton/quotidian/llms.txt Convert between tuple TypeReprs and lists, construct tuples, access companion objects, and inspect field types. Use `.unapplied` to strip type arguments and `.valueAs` to extract literal constants. ```scala import quotidian.syntax.* import scala.quoted.* def typeReprExamples(using Quotes): Unit = import quotes.reflect.* // tupleToList: convert a Tuple TypeRepr into a List[TypeRepr] val tupleType = TypeRepr.of[(Int, String, Boolean)] // Not directly a HKT tuple in reflect, but via Mirror: // TypeRepr.of[types].tupleToList → List(TypeRepr.of[Int], TypeRepr.of[String], ...) // TypeRepr.makeTuple: build a *: chain from a List[TypeRepr] val reconstructed = TypeRepr.makeTuple(List(TypeRepr.of[Int], TypeRepr.of[String])) // equivalent to TypeRepr.of[Int *: String *: EmptyTuple] // TypeRepr.makeTupleClass: build a TupleN type (Tuple2[Int, String]) val tupleClass = TypeRepr.makeTupleClass(List(TypeRepr.of[Int], TypeRepr.of[String])) // TypeRepr.companionOf / TypeRepr.companionClassOf val companionRef = TypeRepr.companionOf[Option[Int]] // Expr companion module val companionClassRef = TypeRepr.companionClassOf[Option[Int]] // TypeRepr.fieldTypes: list the field types of a product val fieldTypesOfPerson = TypeRepr.fieldTypes[case class Temp(x: Int, y: String)] // .unapplied: strip type arguments → Option[Int].unapplied == Option val baseOption = TypeRepr.of[Option[Int]].unapplied // .valueAs[A]: extract a literal constant value from a TypeRepr // Used internally for MirroredLabel extraction ``` -------------------------------- ### Derive FromExpr and ToExpr for Case Classes and Enums Source: https://context7.com/kitlangton/quotidian/llms.txt Use the 'derives' keyword to automatically generate FromExpr and ToExpr instances for case classes, enums, and sealed traits. This eliminates manual quoting boilerplate when working with compile-time expressions. ```scala import quotidian.* import scala.quoted.* // Case class with nested types case class Pet(name: String, hasBone: Boolean, favoritePerson: Option[Person]) derives FromExpr, ToExpr case class Person(name: String, age: Int, pet: Pet) derives FromExpr, ToExpr // Enum with case classes enum Fruit derives FromExpr, ToExpr: case Apple(variety: String) case Orange(juiciness: Int) case Banana(isYellow: Boolean) // Sealed trait hierarchy sealed trait Job extends Product with Serializable derives FromExpr, ToExpr object Job: case class Developer(name: String, tickets: Int) extends Job case class Manager(name: String, isBusy: Boolean) extends Job case object Lump extends Job // Usage inside a macro — Expr.unapply delegates to the derived FromExpr inline def inspectFruit(inline f: Fruit): String = ${ inspectFruitImpl('f) } def inspectFruitImpl(expr: Expr[Fruit])(using Quotes): Expr[String] = expr match case Expr(Fruit.Apple(variety)) => Expr(s"An apple of variety: $variety") case Expr(Fruit.Orange(juice)) => Expr(s"An orange with juiciness: $juice") case Expr(Fruit.Banana(isYellow)) => Expr(s"A banana, yellow=$isYellow") case _ => Expr("Unknown fruit") // At call site val result = inspectFruit(Fruit.Apple("Granny Smith")) // result: "An apple of variety: Granny Smith" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.