Skip to content

Commit

Permalink
Merge pull request #132 from soronpo/getarg_mods
Browse files Browse the repository at this point in the history
Ovehauling the GetArg functionality
  • Loading branch information
Oron Port authored Apr 5, 2020
2 parents b4bbae4 + ad616c7 commit a2f58c5
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 166 deletions.
218 changes: 123 additions & 95 deletions src/main/scala/singleton/ops/impl/GeneralMacros.scala

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions src/main/scala/singleton/ops/impl/InterpolatorTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package singleton.ops.impl


//This is just for testing the GetArg workaround a problem a string interpolator arguments are applied
protected[singleton] object InterpolatorTest {
trait Bar
trait Tag[W] extends HasOut {
type Out = W
}
type XBar[W] = Bar with Tag[W]

final implicit class InterpolatorSyntax(val sc: StringContext) {
def bar(args: Bar*)(implicit interpolator : Interpolator[Bar]) : interpolator.Out = interpolator.value
}
trait Interpolator[T] extends HasOut {
type Out <: T
val value : Out
}

object Interpolator {
type Aux[T, Out0 <: T] = Interpolator[T]{type Out = Out0}
implicit def ev[W] : Interpolator.Aux[Bar, XBar[W]] = macro Macro.interpolator
}

protected object Macro {
object whitebox { type Context = scala.reflect.macros.whitebox.Context }
def interpolator(c: whitebox.Context) : c.Tree = {
import c.universe._
val widthTpe = c.internal.constantType(Constant(5))

q"""
new singleton.ops.impl.InterpolatorTest.Interpolator[singleton.ops.impl.InterpolatorTest.Bar] {
type Out = singleton.ops.impl.InterpolatorTest.XBar[$widthTpe]
val value : Out = new singleton.ops.impl.InterpolatorTest.Bar{}.asInstanceOf[singleton.ops.impl.InterpolatorTest.XBar[$widthTpe]]
}
"""
}
}
}
9 changes: 7 additions & 2 deletions src/main/scala/singleton/ops/impl/Op.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package singleton.ops.impl

import shapeless.Nat

trait Op extends Serializable {
trait HasOut extends Any with Serializable {
type Out
}

trait Op extends HasOut {
type OutWide
type Out
type OutNat <: Nat
Expand All @@ -23,9 +27,10 @@ protected[singleton] trait OpGen[O <: Op] {type Out; val value : Out}
protected[singleton] object OpGen {
type Aux[O <: Op, Ret_Out] = OpGen[O] {type Out = Ret_Out}
implicit def impl[O <: Op](implicit o: O) : Aux[O, o.Out] = new OpGen[O] {type Out = o.Out; val value = o.value.asInstanceOf[o.Out]}
implicit def getValue[O <: Op, Out](o : Aux[O, Out]) : Out = o.value
}

trait OpCast[T, O <: Op] {type Out <: T; val value : Out}
trait OpCast[T, O <: Op] extends HasOut {type Out <: T; val value : Out}


@scala.annotation.implicitNotFound(msg = "Unable to prove type argument is a Nat.")
Expand Down
1 change: 0 additions & 1 deletion src/main/scala/singleton/ops/impl/OpId.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ object OpId {
sealed trait Arg extends OpId //Argument
sealed trait AcceptNonLiteral extends OpId
sealed trait GetArg extends OpId
sealed trait GetLHSArg extends OpId
sealed trait ImplicitFound extends OpId
sealed trait EnumCount extends OpId
sealed trait ITE extends OpId //If-Then-Else
Expand Down
50 changes: 0 additions & 50 deletions src/main/scala/singleton/ops/impl/OpMacros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,53 +86,3 @@ object OpMacro {
// (implicit op : OpMacro[N, S1, S2, S3]) : ValueOf[OpMacro[N, S1, S2, S3]] = new ValueOf(op)
}
/*******************************************************************************************************/


/********************************************************************************************************
* Get function/class argument's type
*******************************************************************************************************/
object GetArg {
type Aux[ArgIdx, Out0] = GetArg[ArgIdx]{type Out = Out0}

@scala.annotation.implicitNotFound("Argument with index ${ArgIdx} not found")
trait GetArg[ArgIdx] {
type Out
val value : Out
}

object GetArg {
implicit def call[ArgIdx, Out]: Aux[ArgIdx, Out] = macro Macro.impl[ArgIdx]

final class Macro(val c: whitebox.Context) extends GeneralMacros {
def impl[ArgIdx : c.WeakTypeTag]: c.Tree =
MaterializeGetArg(c.symbolOf[GetArg[_]], c.symbolOf[Aux[_,_]], c.weakTypeOf[ArgIdx], false)
}
implicit def toArgValue[I, Out](i : Aux[I, Out]) : Out = i.value
}
}
/*******************************************************************************************************/


/********************************************************************************************************
* Get function/class argument's type
*******************************************************************************************************/
object GetLHSArg {
type Aux[ArgIdx, Out0] = GetLHSArg[ArgIdx]{type Out = Out0}

@scala.annotation.implicitNotFound("Argument with index ${ArgIdx} not found")
trait GetLHSArg[ArgIdx] {
type Out
val value : Out
}

object GetLHSArg {
implicit def call[ArgIdx, Out]: Aux[ArgIdx, Out] = macro Macro.impl[ArgIdx]

final class Macro(val c: whitebox.Context) extends GeneralMacros {
def impl[ArgIdx : c.WeakTypeTag]: c.Tree =
MaterializeGetArg(c.symbolOf[GetLHSArg[_]], c.symbolOf[Aux[_,_]], c.weakTypeOf[ArgIdx], true)
}
implicit def toArgValue[I, Out](i : Aux[I, Out]) : Out = i.value
}
}
/*******************************************************************************************************/
18 changes: 14 additions & 4 deletions src/main/scala/singleton/ops/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,24 @@ package object ops {
protected[singleton] type Arg[Num, T, TWide] = OpMacro[OpId.Arg, Num, T, TWide] //Argument for real-time function creation
protected[singleton] type GetType[Sym] = OpMacro[OpId.GetType, Sym, NP, NP] //Argument for real-time function creation
type AcceptNonLiteral[P1] = OpMacro[OpId.AcceptNonLiteral, P1, NP, NP]
type GetArg[ArgIdx] = OpMacro[OpId.GetArg, ArgIdx, NP, NP] //Use to get argument type of class/definition
type GetLHSArg[ArgIdx] = OpMacro[OpId.GetLHSArg, ArgIdx, NP, NP] //Use to get argument type of the left-hand-side
type GetArg[ArgIdx] = OpMacro[OpId.GetArg, ArgIdx, False, NP] //Use to get argument type of class/definition
type GetLHSArg[ArgIdx] = OpMacro[OpId.GetArg, ArgIdx, True, NP] //Use to get argument type of the left-hand-side
type ImplicitFound[Sym] = OpMacro[OpId.ImplicitFound, GetType[Sym], NP, NP] //Implicit Found boolean indication
type EnumCount[Sym] = OpMacro[OpId.EnumCount, GetType[Sym], NP, NP] //Number of direct subclasses
final val GetArg = impl.GetArg
final val GetLHSArg = impl.GetLHSArg
object GetArg {
type Aux[ArgIdx, Out] = OpAuxGen[GetArg[ArgIdx], Out]
}
object GetLHSArg {
type Aux[ArgIdx, Out] = OpAuxGen[GetLHSArg[ArgIdx], Out]
}
type GetArg0 = GetArg[W.`0`.T]
object GetArg0 {
type Aux[Out] = OpAuxGen[GetArg0, Out]
}
type GetLHSArg0 = GetLHSArg[W.`0`.T]
object GetLHSArg0 {
type Aux[Out] = OpAuxGen[GetLHSArg0, Out]
}
type Id[P1] = OpMacro[OpId.Id, P1, NP, NP]
type ![P1] = OpMacro[OpId.!, P1, NP, NP]
type Require[Cond] = OpMacro[OpId.Require, Cond, DefaultRequireMsg, NoSym]
Expand Down
5 changes: 1 addition & 4 deletions src/main/scala/singleton/twoface/impl/CaseClassSkipper.scala
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
package singleton.twoface.impl

import singleton.ops.impl.HasOut
import singleton.twoface.TwoFace

import scala.reflect.macros.whitebox

trait HasOut {
type Out
}

sealed trait CaseClassSkipper[T <: HasOut] extends HasOut {
type Out
def apply(value : T => Any, fallBack : => Boolean) : Out
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/singleton/twoface/impl/TwoFaceShell.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package singleton.twoface.impl
import singleton.twoface.TwoFace

import singleton.ops.impl.GeneralMacros
import singleton.ops.impl.{GeneralMacros, HasOut}
import scala.reflect.macros.whitebox

////////////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala_2.13+/singleton/twoface/impl/TwoFaceAny.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package singleton.twoface.impl

import singleton.ops._
import singleton.ops.impl.std
import singleton.ops.impl.{std, HasOut}

trait TwoFaceAny[Face, T] extends Any {
trait TwoFaceAny[Face, T] extends Any with HasOut {
type Out = T
def isLiteral(implicit rt : RunTime[T]) : std.Boolean = !rt
@inline def getValue : Face
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala_2.13-/singleton/twoface/impl/TwoFaceAny.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package singleton.twoface.impl

import singleton.ops._
import singleton.ops.impl.{GeneralMacros, std}
import singleton.ops.impl.{GeneralMacros, std, HasOut}

import scala.reflect.macros.whitebox

trait TwoFaceAny[Face, T] extends Any {
trait TwoFaceAny[Face, T] extends Any with HasOut {
type Out = T
def isLiteral(implicit rt : RunTime[T]) : std.Boolean = !rt
@inline def getValue : Face
Expand Down
15 changes: 10 additions & 5 deletions src/test/scala/singleton/ops/GetArgSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,16 @@ class GetArgSpec extends Properties("GetArgSpec") {
illTyped("bad_use")
}

import impl.InterpolatorTest._

trait Foo[W] {
def +[R](that: Foo.Able[R]) : Unit = {}
}


object Foo {

class Able[R](val right : R)

class Able[R](val right: R)
object Able {
implicit def ofXInt[R <: Int](right : Int)(implicit arg: GetArg.Aux[W.`0`.T, R]) : Able[R] = new Able[R](arg)
implicit def ofBar[R <: Bar](right: Bar)(implicit arg: GetArg0.Aux[R]): Able[R] = new Able[R](right.asInstanceOf[R])
}
}
def foo(i: Int) = i
Expand All @@ -86,4 +84,11 @@ class GetArgSpec extends Properties("GetArgSpec") {
Foo.Able.ofXInt(foo(one + one))
}

property("GetArg with string interpolation inputs") = wellTyped {
val z = new Foo[W.`5`.T] {}
val b5 = bar"5"
z + b5
z + bar"5"
}

}

0 comments on commit a2f58c5

Please sign in to comment.