From d5840fc7e339f13fb0c8cc8fe027cd5b79ac9609 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 27 Mar 2019 15:23:01 +0100 Subject: [PATCH 1/8] Fix #6150: Emit error when calling Scala 2 macro --- compiler/src/dotty/tools/dotc/profile/Profiler.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Typer.scala | 4 ++++ compiler/test/dotty/tools/backend/jvm/AsmNode.scala | 4 ++-- project/Build.scala | 6 ++++++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/profile/Profiler.scala b/compiler/src/dotty/tools/dotc/profile/Profiler.scala index ecb9696a7fd5..69d493b78f3f 100644 --- a/compiler/src/dotty/tools/dotc/profile/Profiler.scala +++ b/compiler/src/dotty/tools/dotc/profile/Profiler.scala @@ -228,7 +228,7 @@ object ConsoleProfileReporter extends ProfileReporter { } override def reportGc(data: GcEventData): Unit = { - println(f"Profiler GC reported ${data.gcEndMillis - data.gcStartMillis}ms") + println(s"Profiler GC reported ${data.gcEndMillis - data.gcStartMillis}ms") } } diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 1c81ef0ec665..abbe4e6d599e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2753,6 +2753,10 @@ class Typer extends Namer tree.tpe <:< wildApprox(pt) readaptSimplified(Inliner.inlineCall(tree, pt)) } + else if (tree.symbol.is(Macro, butNot = Inline)) { + ctx.error("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) + tree + } else if (tree.tpe <:< pt) { if (pt.hasAnnotation(defn.InlineParamAnnot)) checkInlineConformant(tree, isFinal = false, "argument to inline parameter") diff --git a/compiler/test/dotty/tools/backend/jvm/AsmNode.scala b/compiler/test/dotty/tools/backend/jvm/AsmNode.scala index ac3f34258d67..1100c9054b4d 100644 --- a/compiler/test/dotty/tools/backend/jvm/AsmNode.scala +++ b/compiler/test/dotty/tools/backend/jvm/AsmNode.scala @@ -15,8 +15,8 @@ sealed trait AsmNode[+T] { def attrs: List[Attribute] def visibleAnnotations: List[AnnotationNode] def invisibleAnnotations: List[AnnotationNode] - def characteristics = f"$name%15s $desc%-30s$accessString$sigString" - def erasedCharacteristics = f"$name%15s $desc%-30s$accessString" + def characteristics = "%15s %-30s%s%s".format(name, desc, accessString, sigString) + def erasedCharacteristics = "%15s %-30s%s".format(name, desc, accessString) private def accessString = if (access == 0) "" else " " + Modifier.toString(access) private def sigString = if (signature == null) "" else " " + signature diff --git a/project/Build.scala b/project/Build.scala index 429bab53705d..75b2ce43322f 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -568,6 +568,12 @@ object Build { IO.delete(trgDir) IO.createDirectory(trgDir) IO.unzip(scalaJSIRSourcesJar, trgDir) + + // Remove f interpolator macro call to avoid its expansion while compiling the compiler and the implementation of the f macro + val utilsFile = trgDir / "org/scalajs/ir/Utils.scala" + val patchedSource = IO.read(utilsFile).replace("""f"\\u$c%04x"""", """"\\u%04x".format(c)""") + IO.write(utilsFile, patchedSource) + (trgDir ** "*.scala").get.toSet } (Set(scalaJSIRSourcesJar)).toSeq }.taskValue, From 70de4ec13fa72ca0576fecbbf725b9b9622bd9c2 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 27 Mar 2019 18:16:59 +0100 Subject: [PATCH 2/8] Intrinsify f interpolator --- .../src/dotty/tools/dotc/core/Definitions.scala | 7 +++++++ compiler/src/dotty/tools/dotc/typer/Typer.scala | 10 ++++++++-- .../scala/internal/StringContext.scala | 15 +++++++++++++++ .../scala/internal/StringContext.scala | 8 ++++++++ tests/run-with-compiler/f-interpolator.check | 2 ++ tests/run-with-compiler/f-interpolator.scala | 7 +++++++ 6 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 library/src-bootstrapped/scala/internal/StringContext.scala create mode 100644 library/src-non-bootstrapped/scala/internal/StringContext.scala create mode 100644 tests/run-with-compiler/f-interpolator.check create mode 100644 tests/run-with-compiler/f-interpolator.scala diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 5c1c678dc02c..d423c676e4b8 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -631,10 +631,17 @@ class Definitions { def StringContextS(implicit ctx: Context): Symbol = StringContextSR.symbol lazy val StringContextRawR: TermRef = StringContextClass.requiredMethodRef(nme.raw_) def StringContextRaw(implicit ctx: Context): Symbol = StringContextRawR.symbol + lazy val StringContext_fR: TermRef = StringContextClass.requiredMethodRef(nme.f) + def StringContext_f(implicit ctx: Context): Symbol = StringContext_fR.symbol def StringContextModule(implicit ctx: Context): Symbol = StringContextClass.companionModule lazy val StringContextModule_applyR: TermRef = StringContextModule.requiredMethodRef(nme.apply) def StringContextModule_apply(implicit ctx: Context): Symbol = StringContextModule_applyR.symbol + lazy val InternalStringContextModuleR: TermRef = ctx.requiredModuleRef("scala.internal.StringContext") + def InternalStringContextModule(implicit ctx: Context): Symbol = InternalStringContextModuleR.termSymbol + lazy val InternalStringContextModule_fR: TermRef = InternalStringContextModule.requiredMethodRef(nme.f) + def InternalStringContextModule_f(implicit ctx: Context): Symbol = InternalStringContextModule_fR.symbol + lazy val PartialFunctionType: TypeRef = ctx.requiredClassRef("scala.PartialFunction") def PartialFunctionClass(implicit ctx: Context): ClassSymbol = PartialFunctionType.symbol.asClass lazy val PartialFunction_isDefinedAtR: TermRef = PartialFunctionClass.requiredMethodRef(nme.isDefinedAt) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index abbe4e6d599e..0b3da15b03f7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2754,8 +2754,14 @@ class Typer extends Namer readaptSimplified(Inliner.inlineCall(tree, pt)) } else if (tree.symbol.is(Macro, butNot = Inline)) { - ctx.error("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) - tree + if (tree.symbol eq defn.StringContext_f) { + val Apply(TypeApply(Select(sc, _), _), args) = tree + val newCall = ref(defn.InternalStringContextModule_f).appliedTo(sc).appliedToArgs(args) + Inliner.inlineCall(newCall, pt) + } else { + ctx.error("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) + tree + } } else if (tree.tpe <:< pt) { if (pt.hasAnnotation(defn.InlineParamAnnot)) diff --git a/library/src-bootstrapped/scala/internal/StringContext.scala b/library/src-bootstrapped/scala/internal/StringContext.scala new file mode 100644 index 000000000000..bf8818e871e2 --- /dev/null +++ b/library/src-bootstrapped/scala/internal/StringContext.scala @@ -0,0 +1,15 @@ +package scala.internal + +import scala.quoted._ + +object StringContext { + + inline def f(sc: => scala.StringContext)(args: Any*): String = ${ fImpl('sc, 'args) } + + private def fImpl(sc: Expr[StringContext], args: Expr[Seq[Any]]): Expr[String] = { + // TODO implement f interpolation checks and addapt sc.parts + // See https://github.com/alemannosara/f-interpolators-in-Dotty-macros + '{ $sc.parts.mkString.format($args: _*) } + } + +} diff --git a/library/src-non-bootstrapped/scala/internal/StringContext.scala b/library/src-non-bootstrapped/scala/internal/StringContext.scala new file mode 100644 index 000000000000..b7500e7eea1b --- /dev/null +++ b/library/src-non-bootstrapped/scala/internal/StringContext.scala @@ -0,0 +1,8 @@ +package scala.internal + +object StringContext { + + @forceInline def f(sc: => scala.StringContext)(args: Any*): String = + throw new Exception("non-boostrapped library") + +} diff --git a/tests/run-with-compiler/f-interpolator.check b/tests/run-with-compiler/f-interpolator.check new file mode 100644 index 000000000000..6a350be32166 --- /dev/null +++ b/tests/run-with-compiler/f-interpolator.check @@ -0,0 +1,2 @@ +abc +Hello world diff --git a/tests/run-with-compiler/f-interpolator.scala b/tests/run-with-compiler/f-interpolator.scala new file mode 100644 index 000000000000..385a31d72004 --- /dev/null +++ b/tests/run-with-compiler/f-interpolator.scala @@ -0,0 +1,7 @@ + +object Test { + def main(args: Array[String]): Unit = { + println(f"abc") + println(f"Hello ${"world"}%s") + } +} \ No newline at end of file From 48b66ef6d14b28a5526e7d83bacacf89239a54af Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 27 Mar 2019 20:32:57 +0100 Subject: [PATCH 3/8] Avoid failing with macros in the community build --- community-build/community-projects/ScalaPB | 2 +- community-build/community-projects/scalatest | 2 +- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 1 + compiler/src/dotty/tools/dotc/typer/Typer.scala | 5 ++++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/community-build/community-projects/ScalaPB b/community-build/community-projects/ScalaPB index 329e6d037627..79ecc8db710e 160000 --- a/community-build/community-projects/ScalaPB +++ b/community-build/community-projects/ScalaPB @@ -1 +1 @@ -Subproject commit 329e6d03762799d7c565859eb8df32ea16814a2e +Subproject commit 79ecc8db710e53f07ea12d1dfef80993bbd62e96 diff --git a/community-build/community-projects/scalatest b/community-build/community-projects/scalatest index 8e87031d1674..8e59b4800d4f 160000 --- a/community-build/community-projects/scalatest +++ b/community-build/community-projects/scalatest @@ -1 +1 @@ -Subproject commit 8e87031d16741022bac42d2562961ac9092ca91a +Subproject commit 8e59b4800d4fb247e78a82314afec2ea233325e8 diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 5202666b5414..b3b4b55d19fb 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -77,6 +77,7 @@ class ScalaSettings extends Settings.SettingGroup { val XreplLineWidth: Setting[Int] = IntSetting("-Xrepl-line-width", "Maximal number of columns per line for REPL output", 390) val XfatalWarnings: Setting[Boolean] = BooleanSetting("-Xfatal-warnings", "Fail the compilation if there are any warnings.") val XverifySignatures: Setting[Boolean] = BooleanSetting("-Xverify-signatures", "Verify generic signatures in generated bytecode.") + val XignoreScala2Macros: Setting[Boolean] = BooleanSetting("-Xignore-scala2-macros", "Ignore errors when compiling code that calls Scala2 macros, these will fail at runtime.") val XmixinForceForwarders = ChoiceSetting( name = "-Xmixin-force-forwarders", diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 0b3da15b03f7..c00f0a9c9544 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2754,7 +2754,10 @@ class Typer extends Namer readaptSimplified(Inliner.inlineCall(tree, pt)) } else if (tree.symbol.is(Macro, butNot = Inline)) { - if (tree.symbol eq defn.StringContext_f) { + if (ctx.settings.XignoreScala2Macros.value) { + ctx.warning("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) + tree + } else if (tree.symbol eq defn.StringContext_f) { val Apply(TypeApply(Select(sc, _), _), args) = tree val newCall = ref(defn.InternalStringContextModule_f).appliedTo(sc).appliedToArgs(args) Inliner.inlineCall(newCall, pt) From 89070aebc7df4ec5e3c374711cd5c365305bdcac Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 28 Mar 2019 09:06:25 +0100 Subject: [PATCH 4/8] Fix implementation of f interpolation macro --- .../scala/internal/StringContext.scala | 10 ++++++++-- tests/run-with-compiler/f-interpolator.check | 3 ++- tests/run-with-compiler/f-interpolator.scala | 5 +++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/library/src-bootstrapped/scala/internal/StringContext.scala b/library/src-bootstrapped/scala/internal/StringContext.scala index bf8818e871e2..a10ba805ea41 100644 --- a/library/src-bootstrapped/scala/internal/StringContext.scala +++ b/library/src-bootstrapped/scala/internal/StringContext.scala @@ -7,9 +7,15 @@ object StringContext { inline def f(sc: => scala.StringContext)(args: Any*): String = ${ fImpl('sc, 'args) } private def fImpl(sc: Expr[StringContext], args: Expr[Seq[Any]]): Expr[String] = { - // TODO implement f interpolation checks and addapt sc.parts + // TODO implement f interpolation checks and generate optimal code // See https://github.com/alemannosara/f-interpolators-in-Dotty-macros - '{ $sc.parts.mkString.format($args: _*) } + '{ + // Purely runtime implementation of the f interpolation without any checks + val parts = $sc.parts.toList + assert(parts.nonEmpty, "StringContext should have non empty parts") + val parts2 = parts.head :: parts.tail.map(x => if (x.startsWith("%s")) x else "%s" + x) + parts2.mkString.format($args: _*) + } } } diff --git a/tests/run-with-compiler/f-interpolator.check b/tests/run-with-compiler/f-interpolator.check index 6a350be32166..a937551a56a4 100644 --- a/tests/run-with-compiler/f-interpolator.check +++ b/tests/run-with-compiler/f-interpolator.check @@ -1,2 +1,3 @@ abc -Hello world +Hello world! +Hello world! diff --git a/tests/run-with-compiler/f-interpolator.scala b/tests/run-with-compiler/f-interpolator.scala index 385a31d72004..32a1a4d1d981 100644 --- a/tests/run-with-compiler/f-interpolator.scala +++ b/tests/run-with-compiler/f-interpolator.scala @@ -2,6 +2,7 @@ object Test { def main(args: Array[String]): Unit = { println(f"abc") - println(f"Hello ${"world"}%s") + println(f"Hello ${"world"}%s!") + println(f"Hello ${"world"}!") } -} \ No newline at end of file +} From c9c53b8f734d93af3db78a05a04dc4ed254bfda2 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 28 Mar 2019 09:37:04 +0100 Subject: [PATCH 5/8] Fix #5971: Update Scala 2 macros doc --- docs/docs/reference/dropped-features/macros.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/docs/reference/dropped-features/macros.md b/docs/docs/reference/dropped-features/macros.md index 8a3fa7cd807b..439db916ad25 100644 --- a/docs/docs/reference/dropped-features/macros.md +++ b/docs/docs/reference/dropped-features/macros.md @@ -1,13 +1,12 @@ --- layout: doc-page -title: Dropped: Macros +title: Dropped: Scala 2 Macros --- The previous, experimental macro system has been dropped. Instead, there is a cleaner, more restricted system based on two complementary -concepts: `inline` and `meta`. - -`inline` has been [implemented](../other-new-features/inline.md) in Dotty. - -`meta` is worked on in the separate [Scalameta](http://scalameta.org) project +concepts: `inline` and `'{ ... }`/`${ ... }` code generation. +* `inline` has been [implemented](../other-new-features/inline.md) in Dotty. +* Quotes `'{ ... }` and splices `${ ... }` has been [implemented](../other-new-features/principled-meta-programming.md) in Dotty. + * [TASTy reflect](../other-new-features/tasty-reflect.md) provides more complex tree based APIs to inspect or create quoted code. From c5c5f69739fe83fc0f6d7fd33d9d9ed19fa518af Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 28 Mar 2019 10:01:07 +0100 Subject: [PATCH 6/8] Fix Scala 2 Macro check Previously we checked for `Macro | Scala2x` but the `Scala2x` was on its owner --- compiler/src/dotty/tools/dotc/core/Flags.scala | 3 --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 3 +++ compiler/src/dotty/tools/dotc/typer/RefChecks.scala | 4 ++-- compiler/src/dotty/tools/dotc/typer/Typer.scala | 2 +- tests/neg/override-scala2-macro.check | 3 +++ tests/neg/override-scala2-macro.scala | 3 +++ 6 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 tests/neg/override-scala2-macro.check create mode 100644 tests/neg/override-scala2-macro.scala diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 67dc4e6fe687..4aafd2e74fb7 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -661,9 +661,6 @@ object Flags { /** Is a default parameter in Scala 2*/ final val DefaultParameter: FlagConjunction = allOf(Param, DefaultParameterized) - /** A Scala 2 Macro */ - final val Scala2Macro: FlagConjunction = allOf(Macro, Scala2x) - /** A trait that does not need to be initialized */ final val NoInitsTrait: FlagConjunction = allOf(Trait, NoInits) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index e270cd66fdd1..dae8aa99e997 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -807,6 +807,9 @@ object SymDenotations { // we need an inline flag on them only do that // reduceProjection gets access to their rhs + /** Is this a Scala 2 macro */ + final def isScala2Macro(implicit ctx: Context): Boolean = is(Macro) && symbol.owner.is(Scala2x) + /** An erased value or an inline method, excluding @forceInline annotated methods. * The latter have to be kept around to get to parity with Scala. * This is necessary at least until we have full bootstrap. Right now diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 1f04a4c03b6f..da7211a6294c 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -400,10 +400,10 @@ object RefChecks { overrideError("is an extension method, cannot override a normal method") } else if (other.is(Extension) && !member.is(Extension)) { // (1.9.2) overrideError("is a normal method, cannot override an extension method") - } else if ((member.isInlineMethod || member.is(Scala2Macro)) && other.is(Deferred) && + } else if ((member.isInlineMethod || member.isScala2Macro) && other.is(Deferred) && member.extendedOverriddenSymbols.forall(_.is(Deferred))) { // (1.10) overrideError("is an inline method, must override at least one concrete method") - } else if (other.is(Scala2Macro) && !member.is(Scala2Macro)) { // (1.11) + } else if (other.isScala2Macro && !member.isScala2Macro) { // (1.11) overrideError("cannot be used here - only Scala-2 macros can override Scala-2 macros") } else if (!compatibleTypes(memberTp(self), otherTp(self)) && !compatibleTypes(memberTp(upwardsSelf), otherTp(upwardsSelf))) { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c00f0a9c9544..2ad7c517db2e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2753,7 +2753,7 @@ class Typer extends Namer tree.tpe <:< wildApprox(pt) readaptSimplified(Inliner.inlineCall(tree, pt)) } - else if (tree.symbol.is(Macro, butNot = Inline)) { + else if (tree.symbol.isScala2Macro) { if (ctx.settings.XignoreScala2Macros.value) { ctx.warning("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) tree diff --git a/tests/neg/override-scala2-macro.check b/tests/neg/override-scala2-macro.check new file mode 100644 index 000000000000..ff3f0ea88768 --- /dev/null +++ b/tests/neg/override-scala2-macro.check @@ -0,0 +1,3 @@ +<56..56> in override-scala2-macro.scala +error overriding method f in class StringContext of type [A >: Any](args: Seq[A]): String; + method f of type [A >: Any](args: Seq[A]): String cannot be used here - only Scala-2 macros can override Scala-2 macros diff --git a/tests/neg/override-scala2-macro.scala b/tests/neg/override-scala2-macro.scala new file mode 100644 index 000000000000..0bb048fdb0c0 --- /dev/null +++ b/tests/neg/override-scala2-macro.scala @@ -0,0 +1,3 @@ +class Foo extends StringContext { + override inline def f[A >: Any](args: A*): String = ??? // error +} From 4b8f227643befeb410b062404b53b10026b702e9 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 4 Apr 2019 11:00:24 +0200 Subject: [PATCH 7/8] Add a complete description of macros --- docs/docs/reference/dropped-features/macros.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/docs/reference/dropped-features/macros.md b/docs/docs/reference/dropped-features/macros.md index 439db916ad25..ac0b93e1d1c3 100644 --- a/docs/docs/reference/dropped-features/macros.md +++ b/docs/docs/reference/dropped-features/macros.md @@ -3,9 +3,10 @@ layout: doc-page title: Dropped: Scala 2 Macros --- -The previous, experimental macro system has been dropped. Instead, -there is a cleaner, more restricted system based on two complementary -concepts: `inline` and `'{ ... }`/`${ ... }` code generation. +The previous, experimental macro system has been dropped. Instead, there is a cleaner, more restricted system based on two complementary concepts: `inline` and `'{ ... }`/`${ ... }` code generation. +`'{ ... }` delays the compilation of the code and produces an object containing the code, dually `${ ... }` evaluates an expression which produces code and inserts it in the surrounding `${ ... }`. +In this setting, a definition marked as inlined containing a `${ ... }` is a macro, the code inside the `${ ... }` is executed at compile-time and produces code in the form of `'{ ... }`. +Additionally, the contents of code can be inspected and created with a more complex reflection API (TASTy Reflect) as an extension of `'{ ... }`/`${ ... }` framework. * `inline` has been [implemented](../other-new-features/inline.md) in Dotty. * Quotes `'{ ... }` and splices `${ ... }` has been [implemented](../other-new-features/principled-meta-programming.md) in Dotty. From 89412a06ec6ab705fec634da927f8c4de1808d1b Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 4 Apr 2019 11:14:39 +0200 Subject: [PATCH 8/8] Mode internal StringContext.f implementation to dotty package --- compiler/src/dotty/tools/dotc/core/Definitions.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Typer.scala | 7 ++++++- .../{scala => dotty}/internal/StringContext.scala | 3 ++- .../{scala => dotty}/internal/StringContext.scala | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) rename library/src-bootstrapped/{scala => dotty}/internal/StringContext.scala (83%) rename library/src-non-bootstrapped/{scala => dotty}/internal/StringContext.scala (86%) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d423c676e4b8..0af0526cf542 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -637,7 +637,7 @@ class Definitions { lazy val StringContextModule_applyR: TermRef = StringContextModule.requiredMethodRef(nme.apply) def StringContextModule_apply(implicit ctx: Context): Symbol = StringContextModule_applyR.symbol - lazy val InternalStringContextModuleR: TermRef = ctx.requiredModuleRef("scala.internal.StringContext") + lazy val InternalStringContextModuleR: TermRef = ctx.requiredModuleRef("dotty.internal.StringContext") def InternalStringContextModule(implicit ctx: Context): Symbol = InternalStringContextModuleR.termSymbol lazy val InternalStringContextModule_fR: TermRef = InternalStringContextModule.requiredMethodRef(nme.f) def InternalStringContextModule_f(implicit ctx: Context): Symbol = InternalStringContextModule_fR.symbol diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 2ad7c517db2e..477d4d06270d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2755,9 +2755,14 @@ class Typer extends Namer } else if (tree.symbol.isScala2Macro) { if (ctx.settings.XignoreScala2Macros.value) { - ctx.warning("Scala 2 macro cannot be used in Dotty. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) + ctx.warning("Scala 2 macro cannot be used in Dotty, this call will crash at runtime. See http://dotty.epfl.ch/docs/reference/dropped-features/macros.html", tree.sourcePos) tree } else if (tree.symbol eq defn.StringContext_f) { + // As scala.StringContext.f is defined in the standard library which + // we currently do not bootstrap we cannot implement the macro the library. + // To overcome the current limitation we intercept the call and rewrite it into + // a call to dotty.internal.StringContext.f which we can implement using the new macros. + // As the macro is implemented in the bootstrapped library, it can only be used from the bootstrapped compiler. val Apply(TypeApply(Select(sc, _), _), args) = tree val newCall = ref(defn.InternalStringContextModule_f).appliedTo(sc).appliedToArgs(args) Inliner.inlineCall(newCall, pt) diff --git a/library/src-bootstrapped/scala/internal/StringContext.scala b/library/src-bootstrapped/dotty/internal/StringContext.scala similarity index 83% rename from library/src-bootstrapped/scala/internal/StringContext.scala rename to library/src-bootstrapped/dotty/internal/StringContext.scala index a10ba805ea41..04279c602c4c 100644 --- a/library/src-bootstrapped/scala/internal/StringContext.scala +++ b/library/src-bootstrapped/dotty/internal/StringContext.scala @@ -1,9 +1,10 @@ -package scala.internal +package dotty.internal import scala.quoted._ object StringContext { + /** Implemetation of scala.StringContext.f used in Dotty while the standard library is still not bootstrapped */ inline def f(sc: => scala.StringContext)(args: Any*): String = ${ fImpl('sc, 'args) } private def fImpl(sc: Expr[StringContext], args: Expr[Seq[Any]]): Expr[String] = { diff --git a/library/src-non-bootstrapped/scala/internal/StringContext.scala b/library/src-non-bootstrapped/dotty/internal/StringContext.scala similarity index 86% rename from library/src-non-bootstrapped/scala/internal/StringContext.scala rename to library/src-non-bootstrapped/dotty/internal/StringContext.scala index b7500e7eea1b..c09d39b67b3f 100644 --- a/library/src-non-bootstrapped/scala/internal/StringContext.scala +++ b/library/src-non-bootstrapped/dotty/internal/StringContext.scala @@ -1,4 +1,4 @@ -package scala.internal +package dotty.internal object StringContext {