From 0c54fb51ecea01d1efdd1e7e33a618cde1beaeae Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 19 Sep 2019 17:00:22 +0200 Subject: [PATCH 1/6] Do not hardcode primitive liftables --- .../dotty/tools/dotc/core/Definitions.scala | 1 + .../tools/dotc/transform/ReifyQuotes.scala | 21 +++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 7162b67e6691..87b1106a9d10 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -635,6 +635,7 @@ class Definitions { @tu lazy val QuoteContextModule: Symbol = QuoteContextClass.companionModule @tu lazy val QuoteContext_macroContext: Symbol = QuoteContextModule.requiredMethod("macroContext") + @tu lazy val LiftableClass: ClassSymbol = ctx.requiredClass("scala.quoted.Liftable") @tu lazy val LiftableModule: Symbol = ctx.requiredModule("scala.quoted.Liftable") @tu lazy val InternalQuotedModule: Symbol = ctx.requiredModule("scala.internal.Quoted") diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 8aa8fd7f0542..330d819e5d0c 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -206,24 +206,19 @@ class ReifyQuotes extends MacroTransform { qctx } - def liftedValue[T](value: T, name: TermName) = - ref(defn.LiftableModule) - .select(name).appliedToType(originalTp) - .select("toExpr".toTermName).appliedTo(Literal(Constant(value))) + def liftedValue[T](const: Constant) = { + val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(const)) + val liftable = ctx.typer.inferImplicitArg(ltp, body.span) + if (liftable.tpe.isInstanceOf[SearchFailureType]) + ctx.error(ctx.typer.missingArgMsg(liftable, ltp, "Could no optimize constant in quote"), ctx.source.atSpan(body.span)) + liftable.select("toExpr".toTermName).appliedTo(Literal(const)) + } def pickleAsValue[T](value: T) = value match { case null => ref(defn.QuotedExprModule).select("nullExpr".toTermName) case _: Unit => ref(defn.QuotedExprModule).select("unitExpr".toTermName) - case _: Boolean => liftedValue(value, "Liftable_Boolean_delegate".toTermName) - case _: Byte => liftedValue(value, "Liftable_Byte_delegate".toTermName) - case _: Short => liftedValue(value, "Liftable_Short_delegate".toTermName) - case _: Int => liftedValue(value, "Liftable_Int_delegate".toTermName) - case _: Long => liftedValue(value, "Liftable_Long_delegate".toTermName) - case _: Float => liftedValue(value, "Liftable_Float_delegate".toTermName) - case _: Double => liftedValue(value, "Liftable_Double_delegate".toTermName) - case _: Char => liftedValue(value, "Liftable_Char_delegate".toTermName) - case _: String => liftedValue(value, "Liftable_String_delegate".toTermName) + case _ => liftedValue(Constant(value)) } def pickleAsTasty() = { From a070d552ff0fc755e5d8da8c8ffa83876d4386ed Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 19 Sep 2019 17:09:24 +0200 Subject: [PATCH 2/6] Rename primitive liftable to remove `delegate` in name --- .../scala/quoted/Liftable.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/src-bootstrapped/scala/quoted/Liftable.scala b/library/src-bootstrapped/scala/quoted/Liftable.scala index 3a06170c1431..7d9efd98b0f9 100644 --- a/library/src-bootstrapped/scala/quoted/Liftable.scala +++ b/library/src-bootstrapped/scala/quoted/Liftable.scala @@ -19,15 +19,15 @@ trait Liftable[T] { */ object Liftable { - given Liftable_Boolean_delegate[T <: Boolean] : Liftable[T] = new PrimitiveLiftable - given Liftable_Byte_delegate[T <: Byte] : Liftable[T] = new PrimitiveLiftable - given Liftable_Short_delegate[T <: Short] : Liftable[T] = new PrimitiveLiftable - given Liftable_Int_delegate[T <: Int] : Liftable[T] = new PrimitiveLiftable - given Liftable_Long_delegate[T <: Long] : Liftable[T] = new PrimitiveLiftable - given Liftable_Float_delegate[T <: Float] : Liftable[T] = new PrimitiveLiftable - given Liftable_Double_delegate[T <: Double] : Liftable[T] = new PrimitiveLiftable - given Liftable_Char_delegate[T <: Char] : Liftable[T] = new PrimitiveLiftable - given Liftable_String_delegate[T <: String] : Liftable[T] = new PrimitiveLiftable + given BooleanIsLiftable[T <: Boolean] : Liftable[T] = new PrimitiveLiftable + given ByteIsLiftable[T <: Byte] : Liftable[T] = new PrimitiveLiftable + given ShortIsLiftable[T <: Short] : Liftable[T] = new PrimitiveLiftable + given IntIsLiftable[T <: Int] : Liftable[T] = new PrimitiveLiftable + given LongIsLiftable[T <: Long] : Liftable[T] = new PrimitiveLiftable + given FloatIsLiftable[T <: Float] : Liftable[T] = new PrimitiveLiftable + given DoubleIsLiftable[T <: Double] : Liftable[T] = new PrimitiveLiftable + given CharIsLiftable[T <: Char] : Liftable[T] = new PrimitiveLiftable + given StringIsLiftable[T <: String] : Liftable[T] = new PrimitiveLiftable private class PrimitiveLiftable[T <: Unit | Null | Int | Boolean | Byte | Short | Int | Long | Float | Double | Char | String] extends Liftable[T] { /** Lift a primitive value `n` into `'{ n }` */ From 719f089e38353ff0e8408df92416e04ca3f40fcb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 19 Sep 2019 17:19:34 +0200 Subject: [PATCH 3/6] Work directly on literals --- .../tools/dotc/transform/ReifyQuotes.scala | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 330d819e5d0c..f99455304030 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -206,19 +206,16 @@ class ReifyQuotes extends MacroTransform { qctx } - def liftedValue[T](const: Constant) = { - val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(const)) - val liftable = ctx.typer.inferImplicitArg(ltp, body.span) - if (liftable.tpe.isInstanceOf[SearchFailureType]) - ctx.error(ctx.typer.missingArgMsg(liftable, ltp, "Could no optimize constant in quote"), ctx.source.atSpan(body.span)) - liftable.select("toExpr".toTermName).appliedTo(Literal(const)) - } - - def pickleAsValue[T](value: T) = - value match { - case null => ref(defn.QuotedExprModule).select("nullExpr".toTermName) - case _: Unit => ref(defn.QuotedExprModule).select("unitExpr".toTermName) - case _ => liftedValue(Constant(value)) + def pickleAsLiteral(lit: Literal) = + lit.const.tag match { + case Constants.NullTag => ref(defn.QuotedExprModule).select("nullExpr".toTermName) + case Constants.UnitTag => ref(defn.QuotedExprModule).select("unitExpr".toTermName) + case _ => // Lifted literal + val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(lit.const)) + val liftable = ctx.typer.inferImplicitArg(ltp, body.span) + if (liftable.tpe.isInstanceOf[SearchFailureType]) + ctx.error(ctx.typer.missingArgMsg(liftable, ltp, "Could no optimize constant in quote"), ctx.source.atSpan(body.span)) + liftable.select("toExpr".toTermName).appliedTo(lit) } def pickleAsTasty() = { @@ -238,8 +235,8 @@ class ReifyQuotes extends MacroTransform { if (splices.isEmpty && body.symbol.isPrimitiveValueClass) tag(s"${body.symbol.name}Tag") else pickleAsTasty().select(nme.apply).appliedTo(qctx) } - else toValue(body) match { - case Some(value) => pickleAsValue(value) + else getLiteral(body) match { + case Some(lit) => pickleAsLiteral(lit) case _ => pickleAsTasty() } } @@ -424,10 +421,10 @@ object ReifyQuotes { val name: String = "reifyQuotes" - def toValue(tree: tpd.Tree): Option[Any] = tree match { - case Literal(Constant(c)) => Some(c) - case Block(Nil, e) => toValue(e) - case Inlined(_, Nil, e) => toValue(e) + def getLiteral(tree: tpd.Tree): Option[Literal] = tree match { + case tree: Literal => Some(tree) + case Block(Nil, e) => getLiteral(e) + case Inlined(_, Nil, e) => getLiteral(e) case _ => None } From 4d23595bc9fdddf9ef47b784dec7d6ca86ed2f28 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 19 Sep 2019 17:28:59 +0200 Subject: [PATCH 4/6] Add missing names to StdNames --- compiler/src/dotty/tools/dotc/core/StdNames.scala | 3 +++ compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index a7b6d9154a25..fe2746e50987 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -503,6 +503,7 @@ object StdNames { val notifyAll_ : N = "notifyAll" val notify_ : N = "notify" val null_ : N = "null" + val nullExpr: N = "nullExpr" val ofDim: N = "ofDim" val opaque: N = "opaque" val ordinal: N = "ordinal" @@ -556,6 +557,7 @@ object StdNames { val thisPrefix : N = "thisPrefix" val throw_ : N = "throw" val toArray: N = "toArray" + val toExpr: N = "toExpr" val toList: N = "toList" val toObjectArray : N = "toObjectArray" val toSeq: N = "toSeq" @@ -569,6 +571,7 @@ object StdNames { val unapply: N = "unapply" val unapplySeq: N = "unapplySeq" val unbox: N = "unbox" + val unitExpr: N = "unitExpr" val universe: N = "universe" val update: N = "update" val updateDynamic: N = "updateDynamic" diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index f99455304030..2a8fb04af608 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -208,14 +208,14 @@ class ReifyQuotes extends MacroTransform { def pickleAsLiteral(lit: Literal) = lit.const.tag match { - case Constants.NullTag => ref(defn.QuotedExprModule).select("nullExpr".toTermName) - case Constants.UnitTag => ref(defn.QuotedExprModule).select("unitExpr".toTermName) + case Constants.NullTag => ref(defn.QuotedExprModule).select(nme.nullExpr) + case Constants.UnitTag => ref(defn.QuotedExprModule).select(nme.unitExpr) case _ => // Lifted literal val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(lit.const)) val liftable = ctx.typer.inferImplicitArg(ltp, body.span) if (liftable.tpe.isInstanceOf[SearchFailureType]) ctx.error(ctx.typer.missingArgMsg(liftable, ltp, "Could no optimize constant in quote"), ctx.source.atSpan(body.span)) - liftable.select("toExpr".toTermName).appliedTo(lit) + liftable.select(nme.toExpr).appliedTo(lit) } def pickleAsTasty() = { From a92cfcbccc9671453415e4feb265e6d7fa1573a4 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 19 Sep 2019 17:33:28 +0200 Subject: [PATCH 5/6] Add unitExpr and nullExpr to defn --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 ++ compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 87b1106a9d10..d8e9daf231df 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -630,6 +630,8 @@ class Definitions { @tu lazy val QuotedExprClass: ClassSymbol = ctx.requiredClass("scala.quoted.Expr") @tu lazy val QuotedExprModule: Symbol = QuotedExprClass.companionModule + @tu lazy val QuotedExprModule_nullExpr: Symbol = QuotedExprModule.requiredMethod(nme.nullExpr) + @tu lazy val QuotedExprModule_unitExpr: Symbol = QuotedExprModule.requiredMethod(nme.unitExpr) @tu lazy val QuoteContextClass: ClassSymbol = ctx.requiredClass("scala.quoted.QuoteContext") @tu lazy val QuoteContextModule: Symbol = QuoteContextClass.companionModule diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index 2a8fb04af608..ff7b4081a12a 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -208,8 +208,8 @@ class ReifyQuotes extends MacroTransform { def pickleAsLiteral(lit: Literal) = lit.const.tag match { - case Constants.NullTag => ref(defn.QuotedExprModule).select(nme.nullExpr) - case Constants.UnitTag => ref(defn.QuotedExprModule).select(nme.unitExpr) + case Constants.NullTag => ref(defn.QuotedExprModule_nullExpr) + case Constants.UnitTag => ref(defn.QuotedExprModule_unitExpr) case _ => // Lifted literal val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(lit.const)) val liftable = ctx.typer.inferImplicitArg(ltp, body.span) From 186febaf4241c3fd1cf9b5d3ff5de293ba04cb44 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 24 Sep 2019 11:17:46 +0200 Subject: [PATCH 6/6] Hardcode the lifters as definitions --- .../dotty/tools/dotc/core/Definitions.scala | 10 +++++++++- .../tools/dotc/transform/ReifyQuotes.scala | 20 ++++++++++++------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d8e9daf231df..064d4ae97ede 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -637,8 +637,16 @@ class Definitions { @tu lazy val QuoteContextModule: Symbol = QuoteContextClass.companionModule @tu lazy val QuoteContext_macroContext: Symbol = QuoteContextModule.requiredMethod("macroContext") - @tu lazy val LiftableClass: ClassSymbol = ctx.requiredClass("scala.quoted.Liftable") @tu lazy val LiftableModule: Symbol = ctx.requiredModule("scala.quoted.Liftable") + @tu lazy val LiftableModule_BooleanIsLiftable: Symbol = LiftableModule.requiredMethod("BooleanIsLiftable") + @tu lazy val LiftableModule_ByteIsLiftable: Symbol = LiftableModule.requiredMethod("ByteIsLiftable") + @tu lazy val LiftableModule_ShortIsLiftable: Symbol = LiftableModule.requiredMethod("ShortIsLiftable") + @tu lazy val LiftableModule_IntIsLiftable: Symbol = LiftableModule.requiredMethod("IntIsLiftable") + @tu lazy val LiftableModule_LongIsLiftable: Symbol = LiftableModule.requiredMethod("LongIsLiftable") + @tu lazy val LiftableModule_FloatIsLiftable: Symbol = LiftableModule.requiredMethod("FloatIsLiftable") + @tu lazy val LiftableModule_DoubleIsLiftable: Symbol = LiftableModule.requiredMethod("DoubleIsLiftable") + @tu lazy val LiftableModule_CharIsLiftable: Symbol = LiftableModule.requiredMethod("CharIsLiftable") + @tu lazy val LiftableModule_StringIsLiftable: Symbol = LiftableModule.requiredMethod("StringIsLiftable") @tu lazy val InternalQuotedModule: Symbol = ctx.requiredModule("scala.internal.Quoted") @tu lazy val InternalQuoted_exprQuote : Symbol = InternalQuotedModule.requiredMethod("exprQuote") diff --git a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala index ff7b4081a12a..b17efa5c5e22 100644 --- a/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala +++ b/compiler/src/dotty/tools/dotc/transform/ReifyQuotes.scala @@ -206,17 +206,23 @@ class ReifyQuotes extends MacroTransform { qctx } - def pickleAsLiteral(lit: Literal) = + def pickleAsLiteral(lit: Literal) = { + def liftedValue(lifter: Symbol) = + ref(lifter).appliedToType(originalTp).select(nme.toExpr).appliedTo(lit) lit.const.tag match { case Constants.NullTag => ref(defn.QuotedExprModule_nullExpr) case Constants.UnitTag => ref(defn.QuotedExprModule_unitExpr) - case _ => // Lifted literal - val ltp = defn.LiftableClass.typeRef.appliedTo(ConstantType(lit.const)) - val liftable = ctx.typer.inferImplicitArg(ltp, body.span) - if (liftable.tpe.isInstanceOf[SearchFailureType]) - ctx.error(ctx.typer.missingArgMsg(liftable, ltp, "Could no optimize constant in quote"), ctx.source.atSpan(body.span)) - liftable.select(nme.toExpr).appliedTo(lit) + case Constants.BooleanTag => liftedValue(defn.LiftableModule_BooleanIsLiftable) + case Constants.ByteTag => liftedValue(defn.LiftableModule_ByteIsLiftable) + case Constants.ShortTag => liftedValue(defn.LiftableModule_ShortIsLiftable) + case Constants.IntTag => liftedValue(defn.LiftableModule_IntIsLiftable) + case Constants.LongTag => liftedValue(defn.LiftableModule_LongIsLiftable) + case Constants.FloatTag => liftedValue(defn.LiftableModule_FloatIsLiftable) + case Constants.DoubleTag => liftedValue(defn.LiftableModule_DoubleIsLiftable) + case Constants.CharTag => liftedValue(defn.LiftableModule_CharIsLiftable) + case Constants.StringTag => liftedValue(defn.LiftableModule_StringIsLiftable) } + } def pickleAsTasty() = { val meth =