diff options
author | Paul Phillips <paulp@improving.org> | 2013-09-27 12:27:03 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-09-27 12:27:03 -0700 |
commit | 4b89ce639912d2143cc06ddb3b7da77c8fa8521d (patch) | |
tree | ad7ae6d611ef27e88147917bd266cbcf9e6e5d5c /src/compiler | |
parent | d1e44d85a24aae9a83314fca5de07cf48e3e76ba (diff) | |
parent | 69ce27434e07c8dc215490256fe51622d768dd7e (diff) | |
download | scala-4b89ce639912d2143cc06ddb3b7da77c8fa8521d.tar.gz scala-4b89ce639912d2143cc06ddb3b7da77c8fa8521d.tar.bz2 scala-4b89ce639912d2143cc06ddb3b7da77c8fa8521d.zip |
Merge pull request #2978 from som-snytt/issue/7848-forgotten-interp-msg-lgtm
SI-7848 Xlint no warn on $sym with params
Diffstat (limited to 'src/compiler')
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 f893e4f0ff..dc8c26c926 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 f3aed66bc5..d60e61df1b 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 d88a615c7f..311c0e09e3 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4878,18 +4878,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 @@ -4904,7 +4908,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) |