Skip to content

Commit

Permalink
Add implicit lifting to Squid
Browse files Browse the repository at this point in the history
This allows generating ClosedCode[T] implicits based on T implicits,
possibly using cross-stage persistence to pick up local evidence.
  • Loading branch information
LPTK committed Dec 20, 2018
1 parent 360fdf8 commit b39538e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
10 changes: 10 additions & 0 deletions core/src/main/scala/squid/quasi/QuasiBase.scala
Expand Up @@ -342,6 +342,16 @@ self: Base =>

}

object ImplicitLifting {
import scala.language.experimental.macros
implicit def liftImplicit[T](implicit cde: T): ClosedCode[T] = macro QuasiBlackboxMacros.liftImpl[T]

// TODO Also possible to do: implicitly convert normal code to lifted code:
//import scala.language.implicitConversions
//implicit def apply[T](cde: T): Staged[T] = macro liftImplicitImpl[T]
//def dbg[T](cde: T): Staged[T] = macro liftImplicitImpl[T]
}


/** For easier migration from code bases that used the old `IR`-named interfaces */
val LegacyPredef = new LegacyPredef{}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/squid/quasi/QuasiEmbedder.scala
Expand Up @@ -348,7 +348,7 @@ class QuasiEmbedder[C <: blackbox.Context](val c: C) {

def requireCrossStageEnabled = {
if (!(baseTree.tpe <:< typeOf[CrossStageEnabled]))
throw EmbeddingException(s"Cannot use cross-stage reference: base ${baseTree} does not extend squid.lang.CrossStageEnabled.")
throw EmbeddingException(s"Cannot use cross-stage reference: base ${baseTree} does not implement squid.lang.CrossStageEnabled.")
}

/** Embeds the type checked code with ModularEmbedding, but via the config.embed function, which may make the embedded
Expand Down
10 changes: 10 additions & 0 deletions core/src/main/scala/squid/quasi/QuasiMacros.scala
Expand Up @@ -548,6 +548,16 @@ class QuasiBlackboxMacros(val c: blackbox.Context) {



def liftImpl[T: WeakTypeTag](cde: Tree): Tree = {

c.macroApplication match {
case q"$qc.ImplicitLifting.liftImplicit[$tp]($cde)" =>
debug("Found liftImplicit base: "+qc)
q"$qc.Quasicodes.code[$tp]($cde)"
}

}

def implicitTypeImpl[Config: c.WeakTypeTag, T: c.WeakTypeTag] = wrapError {
val T = weakTypeOf[T]

Expand Down
49 changes: 49 additions & 0 deletions src/test/scala/squid/feature/ImplicitLiftingTests.scala
@@ -0,0 +1,49 @@
// Copyright 2018 EPFL DATA Lab (data.epfl.ch)
//
// 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 squid
package feature

import squid.utils._

class ImplicitLiftingTests extends MyFunSuite(CrossStageDSL) {
import CrossStageDSL.Predef._
import CrossStageDSL.ImplicitLifting._

test("Simple Implicit Lifting") {

implicitly[ClosedCode[Ordering[Int]]] eqt
c"scala.math.Ordering.Int"

implicitly[ClosedCode[Ordering[Int -> Int]]] eqt
c"scala.math.Ordering.Tuple2[scala.Int, scala.Int](scala.math.Ordering.Int, scala.math.Ordering.Int)"

}

class MyClass

test("Cross-Stage Implicit Lifting") {

implicit val ev: Ordering[MyClass] = Ordering.by(_.hashCode) // local instance value

val ordCde = implicitly[ClosedCode[Ordering[MyClass]]]
ordCde eqt c"ev" // cross-stage persistence
assert(ordCde.run == ev)

implicitly[ClosedCode[Ordering[MyClass -> MyClass]]] eqt
c"math.Ordering.Tuple2(ev,ev)"

}

}

0 comments on commit b39538e

Please sign in to comment.