summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala23
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala24
-rw-r--r--test/files/neg/forgot-interpolator.check21
-rw-r--r--test/files/neg/forgot-interpolator.scala24
-rw-r--r--test/files/neg/t2462b.check5
-rw-r--r--test/files/neg/t2462b.flags1
-rw-r--r--test/files/neg/t2462b.scala3
-rw-r--r--test/files/neg/t2462c.check7
-rw-r--r--test/files/neg/t2462c.flags1
-rw-r--r--test/files/neg/t2462c.scala25
-rw-r--r--test/files/neg/t7848-interp-warn.check9
-rw-r--r--test/files/neg/t7848-interp-warn.scala5
14 files changed, 108 insertions, 55 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 1f4d5cbac2..0f7fb98e66 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -145,12 +145,15 @@ trait ContextErrors {
def errMsg = {
val paramName = param.name
val paramTp = param.tpe
+ def evOrParam = (
+ if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX)
+ "evidence parameter of type"
+ else
+ s"parameter $paramName:"
+ )
paramTp.typeSymbolDirect match {
- case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
- case _ =>
- "could not find implicit value for "+
- (if (paramName startsWith nme.EVIDENCE_PARAM_PREFIX) "evidence parameter of type "
- else "parameter "+paramName+": ")+paramTp
+ case ImplicitNotFoundMsg(msg) => msg.format(paramName, paramTp)
+ case _ => s"could not find implicit value for $evOrParam $paramTp"
}
}
issueNormalTypeError(tree, errMsg)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index fbe8cd77fb..b30ae917d9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -1405,13 +1405,15 @@ trait Implicits {
case None => Some("Missing argument `msg` on implicitNotFound annotation.")
})
+ // http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html
+ private val Intersobralator = """\$\{\s*([^}\s]+)\s*\}""".r
class Message(sym: Symbol, msg: String) {
- // http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html
- private def interpolate(text: String, vars: Map[String, String]) = {
- """\$\{([^}]+)\}""".r.replaceAllIn(text, (_: Regex.Match) match {
- case Regex.Groups(v) => java.util.regex.Matcher.quoteReplacement(vars.getOrElse(v, "")) // #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw)
- })}
+ private def interpolate(text: String, vars: Map[String, String]) =
+ Intersobralator.replaceAllIn(text, (_: Regex.Match) match {
+ case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "")
+ // #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw)
+ })
private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName)
@@ -1420,17 +1422,16 @@ trait Implicits {
interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc?
def validate: Option[String] = {
- // is there a shorter way to avoid the intermediate toList?
- val refs = """\$\{([^}]+)\}""".r.findAllIn(msg).matchData.map(_ group 1).toSet
+ val refs = Intersobralator.findAllMatchIn(msg).map(_ group 1).toSet
val decls = typeParamNames.toSet
(refs &~ decls) match {
case s if s.isEmpty => None
- case unboundNames =>
+ case unboundNames =>
val singular = unboundNames.size == 1
- Some("The type parameter"+( if(singular) " " else "s " )+ unboundNames.mkString(", ") +
- " referenced in the message of the @implicitNotFound annotation "+( if(singular) "is" else "are" )+
- " not defined by "+ sym +".")
+ val ess = if (singular) "" else "s"
+ val bee = if (singular) "is" else "are"
+ Some(s"The type parameter$ess ${unboundNames mkString ", "} referenced in the message of the @implicitNotFound annotation $bee not defined by $sym.")
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 32e908e03b..6286463715 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1458,7 +1458,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
applyChecks(sym.annotations)
// validate implicitNotFoundMessage
analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn =>
- unit.warning(tree.pos, "Invalid implicitNotFound message for %s%s:\n%s".format(sym, sym.locationString, warn))
+ unit.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn")
}
case tpt@TypeTree() =>
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 157c6ba4de..b62ab54359 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4875,18 +4875,22 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// Warn about likely interpolated strings which are missing their interpolators
def warnMissingInterpolator(tree: Literal) = if (!isPastTyper) {
- // Unfortunately implicit not found strings looks for all the world like
- // missing interpolators.
- def isArgToImplicitNotFound = context.enclosingApply.tree match {
- case Apply(fn, _) => fn.symbol != null && fn.symbol.enclClass == ImplicitNotFoundClass
- case _ => false
+ // attempt to avoid warning about the special interpolated message string
+ // for implicitNotFound or any standard interpolation (with embedded $$).
+ def isArgToCertainApply = context.enclosingApply.tree match {
+ case Apply(Select(Apply(Ident(n), parts), _), args) if n.toTypeName == StringContextClass.name
+ => true // parts contains tree
+ case Apply(Select(New(Ident(n)), _), _) if n == ImplicitNotFoundClass.name
+ => true
+ case _ => false
}
def warnAbout(s: String) = {
def names = InterpolatorIdentRegex findAllIn s map (n => TermName(n stripPrefix "$"))
- def isSuspiciousExpr = (InterpolatorCodeRegex findFirstIn s).nonEmpty
- //def isSuspiciousName = names exists (lookUp _ andThen (_.exists))
- def suspiciousName = names find (lookUp _ andThen (_.exists))
- def lookUp(n: TermName) = context.lookupSymbol(n, !_.alternatives.exists(symRequiresArg)).symbol
+ def isSuspiciousExpr = (InterpolatorCodeRegex findFirstIn s).nonEmpty
+ //def isSuspiciousName = names exists (lookUp _ andThen isCandidate _)
+ def suspiciousName = names find (n => isCandidate(lookUp(n)))
+ def lookUp(n: TermName) = context.lookupSymbol(n, _ => true).symbol
+ def isCandidate(s: Symbol) = s.exists && s.alternatives.exists(alt => !symRequiresArg(alt))
def symRequiresArg(s: Symbol) = (
s.paramss.nonEmpty
&& (s.paramss.head.headOption filterNot (_.isImplicit)).isDefined
@@ -4901,7 +4905,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
tree.value match {
case Constant(s: String) =>
val noWarn = (
- isArgToImplicitNotFound
+ isArgToCertainApply
|| !(s contains ' ') // another heuristic - e.g. a string with only "$asInstanceOf"
)
if (!noWarn) warnAbout(s)
diff --git a/test/files/neg/forgot-interpolator.check b/test/files/neg/forgot-interpolator.check
index a96431841f..98440fe657 100644
--- a/test/files/neg/forgot-interpolator.check
+++ b/test/files/neg/forgot-interpolator.check
@@ -1,24 +1,21 @@
forgot-interpolator.scala:4: warning: `$bippy` looks like an interpolated identifier! Did you forget the interpolator?
- def f = "Put the $bippy in the $bippy!" // warn
+ def f = "Put the $bippy in the $bippy!" // warn 1
^
forgot-interpolator.scala:14: warning: That looks like an interpolated expression! Did you forget the interpolator?
- def f = """Put the ${println("bippy")} in the bippy!""" // warn
+ def f = """Put the ${println("bippy")} in the bippy!""" // warn 2
^
forgot-interpolator.scala:30: warning: `$beppo` looks like an interpolated identifier! Did you forget the interpolator?
- def f = "$beppo was a marx bros who saw dollars." // warn
+ def f = "$beppo was a marx bros who saw dollars." // warn 3
^
forgot-interpolator.scala:34: warning: `$aleppo` looks like an interpolated identifier! Did you forget the interpolator?
- def f = "$aleppo is a pepper and a city." // warn
+ def f = "$aleppo is a pepper and a city." // warn 4
^
-forgot-interpolator.scala:40: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator?
- def f = "$bar is private, shall we warn just in case?" // warn
+forgot-interpolator.scala:42: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator?
+ def f = "$bar is private, shall we warn just in case?" // warn 5
^
-forgot-interpolator.scala:45: warning: `$hippo` looks like an interpolated identifier! Did you forget the interpolator?
- def h = "$hippo takes an implicit" // warn
+forgot-interpolator.scala:47: warning: `$hippo` looks like an interpolated identifier! Did you forget the interpolator?
+ def h = "$hippo takes an implicit" // warn 6
^
-forgot-interpolator.scala:37: warning: private method in class Bar is never used
- private def bar = 8
- ^
error: No warnings can be incurred under -Xfatal-warnings.
-7 warnings found
+6 warnings found
one error found
diff --git a/test/files/neg/forgot-interpolator.scala b/test/files/neg/forgot-interpolator.scala
index 5067f1dce9..e007f15009 100644
--- a/test/files/neg/forgot-interpolator.scala
+++ b/test/files/neg/forgot-interpolator.scala
@@ -1,7 +1,7 @@
class A {
val bippy = 123
- def f = "Put the $bippy in the $bippy!" // warn
+ def f = "Put the $bippy in the $bippy!" // warn 1
}
class B {
@@ -11,7 +11,7 @@ class B {
}
class C {
- def f = """Put the ${println("bippy")} in the bippy!""" // warn
+ def f = """Put the ${println("bippy")} in the bippy!""" // warn 2
}
package object test {
@@ -27,21 +27,33 @@ package test {
def beppo(i: Int) = 8 * i
def beppo = 8
class Dah extends Doo {
- def f = "$beppo was a marx bros who saw dollars." // warn
+ def f = "$beppo was a marx bros who saw dollars." // warn 3
}
}
class E {
- def f = "$aleppo is a pepper and a city." // warn
+ def f = "$aleppo is a pepper and a city." // warn 4
+ def k = s"Just an interpolation of $aleppo" // no warn
}
class Bar {
private def bar = 8
+ if (bar > 8) ??? // use it to avoid extra warning
}
class Baz extends Bar {
- def f = "$bar is private, shall we warn just in case?" // warn
+ def f = "$bar is private, shall we warn just in case?" // warn 5
}
class G {
def g = "$greppo takes an arg" // no warn
def z = "$zappos takes an arg too" // no warn
- def h = "$hippo takes an implicit" // warn
+ def h = "$hippo takes an implicit" // warn 6
}
+ class J {
+ def j = 8
+ class J2 {
+ def j(i: Int) = 2 * i
+ def jj = "shadowed $j" // no warn
+ }
+ }
+ import annotation._
+ @implicitNotFound("No Z in ${A}") // no warn
+ class Z[A]
}
diff --git a/test/files/neg/t2462b.check b/test/files/neg/t2462b.check
index bc0d9aa469..b3b8007a93 100644
--- a/test/files/neg/t2462b.check
+++ b/test/files/neg/t2462b.check
@@ -6,9 +6,6 @@ t2462b.scala:9: warning: Invalid implicitNotFound message for trait Meh2 in pack
The type parameter Elem referenced in the message of the @implicitNotFound annotation is not defined by trait Meh2.
trait Meh2[-From, +To]
^
-t2462b.scala:12: error: overriding method x in class thankyoupartest of type => Int;
- method x needs `override' modifier
-class testmustfail extends thankyoupartest { def x = 43 }
- ^
+error: No warnings can be incurred under -Xfatal-warnings.
two warnings found
one error found
diff --git a/test/files/neg/t2462b.flags b/test/files/neg/t2462b.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t2462b.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/t2462b.scala b/test/files/neg/t2462b.scala
index 7a1389cc8e..576db4bd3f 100644
--- a/test/files/neg/t2462b.scala
+++ b/test/files/neg/t2462b.scala
@@ -7,6 +7,3 @@ trait Meh[-From, +To]
@implicitNotFound(msg = "Cannot construct a collection of type ${To} ${Elem}.")
trait Meh2[-From, +To]
-
-class thankyoupartest { def x = 42 }
-class testmustfail extends thankyoupartest { def x = 43 }
diff --git a/test/files/neg/t2462c.check b/test/files/neg/t2462c.check
new file mode 100644
index 0000000000..edeead55d6
--- /dev/null
+++ b/test/files/neg/t2462c.check
@@ -0,0 +1,7 @@
+t2462c.scala:18: error: No C of X$Y
+ f[X$Y]
+ ^
+t2462c.scala:24: error: No C of Foo[Int]
+ f[Foo[Int]]
+ ^
+two errors found
diff --git a/test/files/neg/t2462c.flags b/test/files/neg/t2462c.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/t2462c.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/t2462c.scala b/test/files/neg/t2462c.scala
new file mode 100644
index 0000000000..acf04afba9
--- /dev/null
+++ b/test/files/neg/t2462c.scala
@@ -0,0 +1,25 @@
+
+import annotation._
+
+@implicitNotFound("No C of ${ A }")
+class C[A]
+
+trait X$Y
+/* using the $$ separator for expanded names is unwise
+trait X$$Y
+trait X$$$Y
+trait X$$$$Y
+ */
+
+trait Foo[A]
+
+class Test {
+ def f[A: C] = ???
+ f[X$Y]
+/* using the $$ separator for expanded names is unwise
+ f[X$$Y]
+ f[X$$$Y]
+ f[X$$$$Y]
+ */
+ f[Foo[Int]]
+}
diff --git a/test/files/neg/t7848-interp-warn.check b/test/files/neg/t7848-interp-warn.check
index cbdc9f4c27..b7df6d8ce2 100644
--- a/test/files/neg/t7848-interp-warn.check
+++ b/test/files/neg/t7848-interp-warn.check
@@ -1,9 +1,12 @@
-t7848-interp-warn.scala:7: warning: `$foo` looks like an interpolated identifier! Did you forget the interpolator?
+t7848-interp-warn.scala:8: warning: `$foo` looks like an interpolated identifier! Did you forget the interpolator?
"An important $foo message!"
^
-t7848-interp-warn.scala:11: warning: That looks like an interpolated expression! Did you forget the interpolator?
+t7848-interp-warn.scala:12: warning: That looks like an interpolated expression! Did you forget the interpolator?
"A doubly important ${foo * 2} message!"
^
+t7848-interp-warn.scala:16: warning: `$bar` looks like an interpolated identifier! Did you forget the interpolator?
+ def j = s"Try using '${ "something like $bar" }' instead." // warn
+ ^
error: No warnings can be incurred under -Xfatal-warnings.
-two warnings found
+three warnings found
one error found
diff --git a/test/files/neg/t7848-interp-warn.scala b/test/files/neg/t7848-interp-warn.scala
index bb3eeff60c..3887aff8de 100644
--- a/test/files/neg/t7848-interp-warn.scala
+++ b/test/files/neg/t7848-interp-warn.scala
@@ -2,6 +2,7 @@
package test
object Test {
+ def bar = "bar"
def f = {
val foo = "bar"
"An important $foo message!"
@@ -10,4 +11,8 @@ object Test {
val foo = "bar"
"A doubly important ${foo * 2} message!"
}
+ def h = s"Try using '$$bar' instead." // no warn
+ def i = s"Try using '${ "$bar" }' instead." // no warn on space test
+ def j = s"Try using '${ "something like $bar" }' instead." // warn
+ def k = f"Try using '$bar' instead." // no warn on other std interps
}