@@ -10,11 +10,9 @@ import Trees._
1010import NameOps ._
1111import util .SrcPos
1212import config .Feature
13- import java .util .regex .Matcher .quoteReplacement
1413import reporting ._
1514import collection .mutable
1615
17- import scala .util .matching .Regex
1816
1917object ErrorReporting {
2018
@@ -87,18 +85,18 @@ object ErrorReporting {
8785
8886 def expectedTypeStr (tp : Type ): String = tp match {
8987 case tp : PolyProto =>
90- e " type arguments [ ${tp.targs.tpes}%, %] and ${expectedTypeStr(revealDeepenedArgs(tp.resultType))}"
88+ i " type arguments [ ${tp.targs.tpes}%, %] and ${expectedTypeStr(revealDeepenedArgs(tp.resultType))}"
9189 case tp : FunProto =>
9290 def argStr (tp : FunProto ): String =
9391 val result = revealDeepenedArgs(tp.resultType) match {
9492 case restp : FunProto => argStr(restp)
9593 case _ : WildcardType | _ : IgnoredProto => " "
96- case tp => e " and expected result type $tp"
94+ case tp => i " and expected result type $tp"
9795 }
98- e " ( ${tp.typedArgs().tpes}%, %) $result"
96+ i " ( ${tp.typedArgs().tpes}%, %) $result"
9997 s " arguments ${argStr(tp)}"
10098 case _ =>
101- e " expected type $tp"
99+ i " expected type $tp"
102100 }
103101
104102 def anonymousTypeMemberStr (tpe : Type ): String = {
@@ -107,12 +105,12 @@ object ErrorReporting {
107105 case _ : MethodOrPoly => " method"
108106 case _ => " value of type"
109107 }
110- e " $kind $tpe"
108+ i " $kind $tpe"
111109 }
112110
113111 def overloadedAltsStr (alts : List [SingleDenotation ]): String =
114- e " overloaded alternatives of ${denotStr(alts.head)} with types \n " +
115- e " ${alts map (_.info)}% \n % "
112+ i """ overloaded alternatives of ${denotStr(alts.head)} with types
113+ | ${alts map (_.info)}%\n % "" "
116114
117115 def denotStr (denot : Denotation ): String =
118116 if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
@@ -263,195 +261,3 @@ object ErrorReporting {
263261
264262 def err (using Context ): Errors = new Errors
265263}
266-
267- class ImplicitSearchError (
268- arg : tpd.Tree ,
269- pt : Type ,
270- where : String ,
271- paramSymWithMethodCallTree : Option [(Symbol , tpd.Tree )] = None ,
272- ignoredInstanceNormalImport : => Option [SearchSuccess ],
273- importSuggestionAddendum : => String
274- )(using ctx : Context ) {
275-
276- def missingArgMsg = arg.tpe match {
277- case ambi : AmbiguousImplicits =>
278- (ambi.alt1, ambi.alt2) match {
279- case (alt @ AmbiguousImplicitMsg (msg), _) =>
280- userDefinedAmbiguousImplicitMsg(alt, msg)
281- case (_, alt @ AmbiguousImplicitMsg (msg)) =>
282- userDefinedAmbiguousImplicitMsg(alt, msg)
283- case _ =>
284- defaultAmbiguousImplicitMsg(ambi)
285- }
286- case ambi @ TooUnspecific (target) =>
287- ex """ No implicit search was attempted ${location(" for" )}
288- |since the expected type $target is not specific enough """
289- case _ =>
290- val shortMessage = userDefinedImplicitNotFoundParamMessage
291- .orElse(userDefinedImplicitNotFoundTypeMessage)
292- .getOrElse(defaultImplicitNotFoundMessage)
293- formatMsg(shortMessage)()
294- ++ hiddenImplicitsAddendum
295- ++ ErrorReporting .matchReductionAddendum(pt)
296- }
297-
298- private def formatMsg (shortForm : String )(headline : String = shortForm) = arg match
299- case arg : Trees .SearchFailureIdent [? ] =>
300- arg.tpe match
301- case _ : NoMatchingImplicits => headline
302- case tpe : SearchFailureType =>
303- i " $headline. ${tpe.explanation}"
304- case _ => headline
305- case _ =>
306- arg.tpe match
307- case tpe : SearchFailureType =>
308- val original = arg match
309- case Inlined (call, _, _) => call
310- case _ => arg
311- i """ $headline.
312- |I found:
313- |
314- | ${original.show.replace(" \n " , " \n " )}
315- |
316- |But ${tpe.explanation}. """
317- case _ => headline
318-
319- /** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing
320- * all occurrences of `${X}` where `X` is in `paramNames` with the
321- * corresponding shown type in `args`.
322- */
323- private def userDefinedErrorString (raw : String , paramNames : List [String ], args : List [Type ]): String = {
324- def translate (name : String ): Option [String ] = {
325- val idx = paramNames.indexOf(name)
326- if (idx >= 0 ) Some (ex " ${args(idx)}" ) else None
327- }
328-
329- """ \$\{\s*([^}\s]+)\s*\}""" .r.replaceAllIn(raw, (_ : Regex .Match ) match {
330- case Regex .Groups (v) => quoteReplacement(translate(v).getOrElse(" " )).nn
331- })
332- }
333-
334- /** Extract a user defined error message from a symbol `sym`
335- * with an annotation matching the given class symbol `cls`.
336- */
337- private def userDefinedMsg (sym : Symbol , cls : Symbol ) = for {
338- ann <- sym.getAnnotation(cls)
339- msg <- ann.argumentConstantString(0 )
340- } yield msg
341-
342- private def location (preposition : String ) = if (where.isEmpty) " " else s " $preposition $where"
343-
344- private def defaultAmbiguousImplicitMsg (ambi : AmbiguousImplicits ) =
345- s " Ambiguous given instances: ${ambi.explanation}${location(" of" )}"
346-
347- private def defaultImplicitNotFoundMessage =
348- ex " No given instance of type $pt was found ${location(" for" )}"
349-
350- /** Construct a custom error message given an ambiguous implicit
351- * candidate `alt` and a user defined message `raw`.
352- */
353- private def userDefinedAmbiguousImplicitMsg (alt : SearchSuccess , raw : String ) = {
354- val params = alt.ref.underlying match {
355- case p : PolyType => p.paramNames.map(_.toString)
356- case _ => Nil
357- }
358- def resolveTypes (targs : List [tpd.Tree ])(using Context ) =
359- targs.map(a => Inferencing .fullyDefinedType(a.tpe, " type argument" , a.srcPos))
360-
361- // We can extract type arguments from:
362- // - a function call:
363- // @implicitAmbiguous("msg A=${A}")
364- // implicit def f[A](): String = ...
365- // implicitly[String] // found: f[Any]()
366- //
367- // - an eta-expanded function:
368- // @implicitAmbiguous("msg A=${A}")
369- // implicit def f[A](x: Int): String = ...
370- // implicitly[Int => String] // found: x => f[Any](x)
371-
372- val call = tpd.closureBody(alt.tree) // the tree itself if not a closure
373- val targs = tpd.typeArgss(call).flatten
374- val args = resolveTypes(targs)(using ctx.fresh.setTyperState(alt.tstate))
375- userDefinedErrorString(raw, params, args)
376- }
377-
378- /** @param rawMsg Message template with variables, e.g. "Variable A is ${A}"
379- * @param sym Symbol of the annotated type or of the method whose parameter was annotated
380- * @param substituteType Function substituting specific types for abstract types associated with variables, e.g A -> Int
381- */
382- private def formatAnnotationMessage (rawMsg : String , sym : Symbol , substituteType : Type => Type ): String = {
383- val substitutableTypesSymbols = ErrorReporting .substitutableTypeSymbolsInScope(sym)
384-
385- userDefinedErrorString(
386- rawMsg,
387- paramNames = substitutableTypesSymbols.map(_.name.unexpandedName.toString),
388- args = substitutableTypesSymbols.map(_.typeRef).map(substituteType)
389- )
390- }
391-
392- /** Extracting the message from a method parameter, e.g. in
393- *
394- * trait Foo
395- *
396- * def foo(implicit @annotation.implicitNotFound("Foo is missing") foo: Foo): Any = ???
397- */
398- private def userDefinedImplicitNotFoundParamMessage : Option [String ] = paramSymWithMethodCallTree.flatMap { (sym, applTree) =>
399- userDefinedMsg(sym, defn.ImplicitNotFoundAnnot ).map { rawMsg =>
400- val fn = tpd.funPart(applTree)
401- val targs = tpd.typeArgss(applTree).flatten
402- val methodOwner = fn.symbol.owner
403- val methodOwnerType = tpd.qualifier(fn).tpe
404- val methodTypeParams = fn.symbol.paramSymss.flatten.filter(_.isType)
405- val methodTypeArgs = targs.map(_.tpe)
406- val substituteType = (_ : Type ).asSeenFrom(methodOwnerType, methodOwner).subst(methodTypeParams, methodTypeArgs)
407- formatAnnotationMessage(rawMsg, sym.owner, substituteType)
408- }
409- }
410-
411- /** Extracting the message from a type, e.g. in
412- *
413- * @annotation.implicitNotFound("Foo is missing")
414- * trait Foo
415- *
416- * def foo(implicit foo: Foo): Any = ???
417- */
418- private def userDefinedImplicitNotFoundTypeMessage : Option [String ] =
419- def recur (tp : Type ): Option [String ] = tp match
420- case tp : TypeRef =>
421- val sym = tp.symbol
422- userDefinedImplicitNotFoundTypeMessage(sym).orElse(recur(tp.info))
423- case tp : ClassInfo =>
424- tp.baseClasses.iterator
425- .map(userDefinedImplicitNotFoundTypeMessage)
426- .find(_.isDefined).flatten
427- case tp : TypeProxy =>
428- recur(tp.superType)
429- case tp : AndType =>
430- recur(tp.tp1).orElse(recur(tp.tp2))
431- case _ =>
432- None
433- recur(pt)
434-
435- private def userDefinedImplicitNotFoundTypeMessage (sym : Symbol ): Option [String ] =
436- for
437- rawMsg <- userDefinedMsg(sym, defn.ImplicitNotFoundAnnot )
438- if Feature .migrateTo3 || sym != defn.Function1
439- // Don't inherit "No implicit view available..." message if subtypes of Function1 are not treated as implicit conversions anymore
440- yield
441- val substituteType = (_ : Type ).asSeenFrom(pt, sym)
442- formatAnnotationMessage(rawMsg, sym, substituteType)
443-
444- private def hiddenImplicitsAddendum : String =
445- def hiddenImplicitNote (s : SearchSuccess ) =
446- e " \n\n Note: ${s.ref.symbol.showLocated} was not considered because it was not imported with `import given`. "
447-
448- val normalImports = ignoredInstanceNormalImport.map(hiddenImplicitNote)
449-
450- normalImports.getOrElse(importSuggestionAddendum)
451- end hiddenImplicitsAddendum
452-
453- private object AmbiguousImplicitMsg {
454- def unapply (search : SearchSuccess ): Option [String ] =
455- userDefinedMsg(search.ref.symbol, defn.ImplicitAmbiguousAnnot )
456- }
457- }
0 commit comments