Skip to content

Commit 1b45418

Browse files
committed
SI-8013 Nowarn on macro str interpolation
When warning about stray "foo $bar" under `-Xlint`, which may be missing an interpolator id, suppress the warning if we're in the middle of a macro expansion, since we have no useful heuristic to apply to the expanded tree. The test for whether the string is part of an expanded tree is to check all open macros for an expanded tree that contains the literal tree under scrutiny. (This is deemed more paranoid than looking for a macro application that is an enclosing position.)
1 parent 6c63ab1 commit 1b45418

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5107,12 +5107,24 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
51075107

51085108
// Warn about likely interpolated strings which are missing their interpolators
51095109
def warnMissingInterpolator(lit: Literal): Unit = if (!isPastTyper) {
5110+
// attempt to avoid warning about trees munged by macros
5111+
def isMacroExpansion = {
5112+
// context.tree is not the expandee; it is plain new SC(ps).m(args)
5113+
//context.tree exists (t => (t.pos includes lit.pos) && hasMacroExpansionAttachment(t))
5114+
// testing pos works and may suffice
5115+
//openMacros exists (_.macroApplication.pos includes lit.pos)
5116+
// tests whether the lit belongs to the expandee of an open macro
5117+
openMacros exists (_.macroApplication.attachments.get[MacroExpansionAttachment] match {
5118+
case Some(MacroExpansionAttachment(_, t: Tree)) => t exists (_ == lit)
5119+
case _ => false
5120+
})
5121+
}
51105122
// attempt to avoid warning about the special interpolated message string
51115123
// for implicitNotFound or any standard interpolation (with embedded $$).
51125124
def isRecognizablyNotForInterpolation = context.enclosingApply.tree match {
51135125
case Apply(Select(Apply(RefTree(_, nme.StringContext), _), _), _) => true
51145126
case Apply(Select(New(RefTree(_, tpnme.implicitNotFound)), _), _) => true
5115-
case _ => false
5127+
case _ => isMacroExpansion
51165128
}
51175129
def requiresNoArgs(tp: Type): Boolean = tp match {
51185130
case PolyType(_, restpe) => requiresNoArgs(restpe)
@@ -5143,12 +5155,9 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
51435155
}
51445156

51455157
def typedLiteral(tree: Literal) = {
5146-
if (settings.lint)
5147-
warnMissingInterpolator(tree)
5158+
if (settings.lint) warnMissingInterpolator(tree)
51485159

5149-
tree setType (
5150-
if (tree.value.tag == UnitTag) UnitTpe
5151-
else ConstantType(tree.value))
5160+
tree setType (if (tree.value.tag == UnitTag) UnitTpe else ConstantType(tree.value))
51525161
}
51535162

51545163
def typedSingletonTypeTree(tree: SingletonTypeTree) = {

test/files/pos/t8013.flags

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-Xfatal-warnings -Xlint
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* scalac: -Xfatal-warnings -Xlint
3+
*/
4+
package t8013
5+
6+
// unsuspecting user of perverse macro
7+
trait User {
8+
import Perverse.Impervolator
9+
val foo = "bar"
10+
Console println p"Hello, $foo"
11+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
package t8013
3+
4+
// perverse macro to confuse Xlint
5+
6+
import scala.language.experimental.macros
7+
import scala.reflect.macros.{ BlackboxContext => Context }
8+
9+
object Perverse {
10+
11+
implicit class Impervolator(sc: StringContext) {
12+
def p(args: Any*): String = macro pImpl
13+
}
14+
15+
// turn a nice interpolation into something that looks
16+
// nothing like an interpolation or anything we might
17+
// recognize, but which includes a "$id" in an apply.
18+
def pImpl(c: Context)(args: c.Expr[Any]*): c.Expr[String] = {
19+
import c.universe._
20+
val macroPos = c.macroApplication.pos
21+
val text = macroPos.lineContent substring macroPos.column
22+
val tt = Literal(Constant(text))
23+
val tree = q"t8013.Perverse.pervert($tt)"
24+
c.Expr[String](tree)
25+
}
26+
27+
// identity doesn't seem very perverse in this context
28+
//def pervert(text: String): String = text
29+
def pervert(text: String): String = {
30+
Console println s"Perverting [$text]"
31+
text
32+
}
33+
}

0 commit comments

Comments
 (0)