@@ -2,10 +2,12 @@ package dotty.tools.dotc.transform.localopt
22
33import dotty .tools .dotc .ast .Trees ._
44import dotty .tools .dotc .ast .tpd
5+ import dotty .tools .dotc .core .Decorators ._
56import dotty .tools .dotc .core .Constants .Constant
67import dotty .tools .dotc .core .Contexts .Context
78import dotty .tools .dotc .core .StdNames ._
89import dotty .tools .dotc .core .Symbols ._
10+ import dotty .tools .dotc .core .Types .MethodType
911import dotty .tools .dotc .transform .MegaPhase .MiniPhase
1012
1113/**
@@ -21,6 +23,16 @@ class StringInterpolatorOpt extends MiniPhase {
2123
2224 override def phaseName : String = " stringInterpolatorOpt"
2325
26+ override def checkPostCondition (tree : tpd.Tree )(implicit ctx : Context ): Unit = {
27+ tree match {
28+ case tree : RefTree =>
29+ val sym = tree.symbol
30+ assert(sym != defn.StringContext_raw && sym != defn.StringContext_s ,
31+ i " $tree in ${ctx.owner.showLocated} should have been rewritten by phase $phaseName" )
32+ case _ =>
33+ }
34+ }
35+
2436 /** Matches a list of constant literals */
2537 private object Literals {
2638 def unapply (tree : SeqLiteral )(implicit ctx : Context ): Option [List [Literal ]] = {
@@ -60,7 +72,7 @@ class StringInterpolatorOpt extends MiniPhase {
6072 def unapply (tree : Apply )(implicit ctx : Context ): Option [(List [Literal ], List [Tree ])] = {
6173 tree match {
6274 case SOrRawInterpolator (strs, elems) =>
63- if (tree.symbol == defn.StringContextRaw ) Some (strs, elems)
75+ if (tree.symbol == defn.StringContext_raw ) Some (strs, elems)
6476 else { // tree.symbol == defn.StringContextS
6577 try {
6678 val escapedStrs = strs.map { str =>
@@ -80,28 +92,46 @@ class StringInterpolatorOpt extends MiniPhase {
8092 override def transformApply (tree : Apply )(implicit ctx : Context ): Tree = {
8193 val sym = tree.symbol
8294 val isInterpolatedMethod = // Test names first to avoid loading scala.StringContext if not used
83- (sym.name == nme.raw_ && sym.eq(defn.StringContextRaw )) ||
84- (sym.name == nme.s && sym.eq(defn.StringContextS ))
85- if (isInterpolatedMethod) transformInterpolator(tree)
86- else tree
87- }
95+ (sym.name == nme.raw_ && sym.eq(defn.StringContext_raw )) ||
96+ (sym.name == nme.s && sym.eq(defn.StringContext_s ))
97+ if (isInterpolatedMethod)
98+ tree match {
99+ case StringContextIntrinsic (strs : List [Literal ], elems : List [Tree ]) =>
100+ val stri = strs.iterator
101+ val elemi = elems.iterator
102+ var result : Tree = stri.next
103+ def concat (tree : Tree ): Unit = {
104+ result = result.select(defn.String_+ ).appliedTo(tree)
105+ }
106+ while (elemi.hasNext) {
107+ concat(elemi.next)
108+ val str = stri.next
109+ if (! str.const.stringValue.isEmpty) concat(str)
110+ }
111+ result
112+ // Starting with Scala 2.13, s and raw are macros in the standard
113+ // library, so we need to expand them manually.
114+ // sc.s(args) --> standardInterpolator(processEscapes, args, sc.parts)
115+ // sc.raw(args) --> standardInterpolator(x => x, args, sc.parts)
116+ case Apply (intp, args :: Nil ) =>
117+ val pre = intp match {
118+ case Select (pre, _) => pre
119+ case intp : Ident => tpd.desugarIdentPrefix(intp)
120+ }
121+ val isRaw = sym eq defn.StringContext_raw
122+ val stringToString = defn.StringContextModule_processEscapes .info.asInstanceOf [MethodType ]
88123
89- private def transformInterpolator (tree : Tree )(implicit ctx : Context ): Tree = {
90- tree match {
91- case StringContextIntrinsic (strs : List [Literal ], elems : List [Tree ]) =>
92- val stri = strs.iterator
93- val elemi = elems.iterator
94- var result : Tree = stri.next
95- def concat (tree : Tree ): Unit = {
96- result = result.select(defn.String_+ ).appliedTo(tree)
97- }
98- while (elemi.hasNext) {
99- concat(elemi.next)
100- val str = stri.next
101- if (! str.const.stringValue.isEmpty) concat(str)
102- }
103- result
104- case _ => tree
105- }
124+ val process = tpd.Lambda (stringToString, args =>
125+ if (isRaw) args.head else ref(defn.StringContextModule_processEscapes ).appliedToArgs(args))
126+
127+ evalOnce(pre) { sc =>
128+ val parts = sc.select(defn.StringContext_parts )
129+
130+ ref(defn.StringContextModule_standardInterpolator )
131+ .appliedToArgs(List (process, args, parts))
132+ }
133+ }
134+ else
135+ tree
106136 }
107137}
0 commit comments