summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSom Snytt <som.snytt@gmail.com>2013-09-18 18:06:59 -0700
committerSom Snytt <som.snytt@gmail.com>2013-09-23 13:23:24 -0700
commit69ce27434e07c8dc215490256fe51622d768dd7e (patch)
tree827d13297d325a51af6f16ed856734a2e1583a39 /src
parent7d570b54c3c895bc8948adeca2e463d135e38feb (diff)
downloadscala-69ce27434e07c8dc215490256fe51622d768dd7e.tar.gz
scala-69ce27434e07c8dc215490256fe51622d768dd7e.tar.bz2
scala-69ce27434e07c8dc215490256fe51622d768dd7e.zip
SI-7848 Xlint no warn on $sym with params
This idea brought to you by retronym. Also improve implicitNotFound detection at typer; and avoid checking the standard interpolation expression for cases like s"some $$x". Some minor refactorings of implicitNotFound strings. The intersobralator allows extra spaces, i.e., trims.
Diffstat (limited to 'src')
-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
4 files changed, 35 insertions, 27 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)