@@ -10,11 +10,9 @@ import Trees._
10
10
import NameOps ._
11
11
import util .SrcPos
12
12
import config .Feature
13
- import java .util .regex .Matcher .quoteReplacement
14
13
import reporting ._
15
14
import collection .mutable
16
15
17
- import scala .util .matching .Regex
18
16
19
17
object ErrorReporting {
20
18
@@ -87,18 +85,18 @@ object ErrorReporting {
87
85
88
86
def expectedTypeStr (tp : Type ): String = tp match {
89
87
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))}"
91
89
case tp : FunProto =>
92
90
def argStr (tp : FunProto ): String =
93
91
val result = revealDeepenedArgs(tp.resultType) match {
94
92
case restp : FunProto => argStr(restp)
95
93
case _ : WildcardType | _ : IgnoredProto => " "
96
- case tp => e " and expected result type $tp"
94
+ case tp => i " and expected result type $tp"
97
95
}
98
- e " ( ${tp.typedArgs().tpes}%, %) $result"
96
+ i " ( ${tp.typedArgs().tpes}%, %) $result"
99
97
s " arguments ${argStr(tp)}"
100
98
case _ =>
101
- e " expected type $tp"
99
+ i " expected type $tp"
102
100
}
103
101
104
102
def anonymousTypeMemberStr (tpe : Type ): String = {
@@ -107,12 +105,12 @@ object ErrorReporting {
107
105
case _ : MethodOrPoly => " method"
108
106
case _ => " value of type"
109
107
}
110
- e " $kind $tpe"
108
+ i " $kind $tpe"
111
109
}
112
110
113
111
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 % "" "
116
114
117
115
def denotStr (denot : Denotation ): String =
118
116
if (denot.isOverloaded) overloadedAltsStr(denot.alternatives)
@@ -263,195 +261,3 @@ object ErrorReporting {
263
261
264
262
def err (using Context ): Errors = new Errors
265
263
}
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