Skip to content

Commit ddd072c

Browse files
committed
Fix implicitNotFound message for type aliases
Fix scala#7092
1 parent 938d405 commit ddd072c

File tree

4 files changed

+76
-21
lines changed

4 files changed

+76
-21
lines changed

compiler/src/dotty/tools/dotc/reporting/messages.scala

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,19 +2784,25 @@ class MissingImplicitArgument(
27842784
val idx = paramNames.indexOf(name)
27852785
if (idx >= 0) Some(i"${args(idx)}") else None
27862786
"""\$\{\s*([^}\s]+)\s*\}""".r.replaceAllIn(raw, (_: Regex.Match) match
2787-
case Regex.Groups(v) => quoteReplacement(translate(v).getOrElse("")).nn
2787+
case Regex.Groups(v) => quoteReplacement(translate(v).getOrElse(v)).nn
27882788
)
27892789

27902790
/** @param rawMsg Message template with variables, e.g. "Variable A is ${A}"
27912791
* @param sym Symbol of the annotated type or of the method whose parameter was annotated
27922792
* @param substituteType Function substituting specific types for abstract types associated with variables, e.g A -> Int
27932793
*/
2794-
def formatAnnotationMessage(rawMsg: String, sym: Symbol, substituteType: Type => Type)(using Context): String =
2794+
def formatAnnotationMessage(
2795+
rawMsg: String,
2796+
sym: Symbol,
2797+
paramNames: List[Name],
2798+
args: List[Type],
2799+
substituteType: Type => Type,
2800+
)(using Context): String =
27952801
val substitutableTypesSymbols = substitutableTypeSymbolsInScope(sym)
27962802
userDefinedErrorString(
27972803
rawMsg,
2798-
paramNames = substitutableTypesSymbols.map(_.name.unexpandedName.toString),
2799-
args = substitutableTypesSymbols.map(_.typeRef).map(substituteType)
2804+
paramNames = (paramNames ::: substitutableTypesSymbols.map(_.name)).map(_.unexpandedName.toString),
2805+
args = args ::: substitutableTypesSymbols.map(_.typeRef).map(substituteType)
28002806
)
28012807

28022808
/** Extract a user defined error message from a symbol `sym`
@@ -2808,14 +2814,17 @@ class MissingImplicitArgument(
28082814
msg <- ann.argumentConstantString(0)
28092815
yield msg
28102816

2811-
def userDefinedImplicitNotFoundTypeMessageFor(sym: Symbol)(using Context): Option[String] =
2812-
for
2813-
rawMsg <- userDefinedMsg(sym, defn.ImplicitNotFoundAnnot)
2814-
if Feature.migrateTo3 || sym != defn.Function1
2815-
// Don't inherit "No implicit view available..." message if subtypes of Function1 are not treated as implicit conversions anymore
2816-
yield
2817-
val substituteType = (_: Type).asSeenFrom(pt, sym)
2818-
formatAnnotationMessage(rawMsg, sym, substituteType)
2817+
def userDefinedImplicitNotFoundTypeMessageFor(
2818+
sym: Symbol,
2819+
params: List[ParamInfo] = Nil,
2820+
args: List[Type] = Nil
2821+
)(using Context): Option[String] = for
2822+
rawMsg <- userDefinedMsg(sym, defn.ImplicitNotFoundAnnot)
2823+
if Feature.migrateTo3 || sym != defn.Function1
2824+
// Don't inherit "No implicit view available..." message if subtypes of Function1 are not treated as implicit conversions anymore
2825+
yield
2826+
val paramNames = params.map(_.paramName)
2827+
formatAnnotationMessage(rawMsg, sym, paramNames, args, _.asSeenFrom(pt, sym))
28192828

28202829
/** Extracting the message from a method parameter, e.g. in
28212830
*
@@ -2830,19 +2839,21 @@ class MissingImplicitArgument(
28302839
val targs = tpd.typeArgss(applTree).flatten
28312840
val methodOwner = fn.symbol.owner
28322841
val methodOwnerType = tpd.qualifier(fn).tpe
2833-
val methodTypeParams = fn.symbol.paramSymss.flatten.filter(_.isType)
2842+
val methodTypeParams = fn.symbol.paramSymss.flatten.withFilter(_.isType).map(_.name)
28342843
val methodTypeArgs = targs.map(_.tpe)
2835-
val substituteType = (_: Type).asSeenFrom(methodOwnerType, methodOwner).subst(methodTypeParams, methodTypeArgs)
2836-
formatAnnotationMessage(rawMsg, sym.owner, substituteType)
2844+
formatAnnotationMessage(rawMsg, sym.owner, methodTypeParams, methodTypeArgs, _.asSeenFrom(methodOwnerType, methodOwner))
28372845

28382846
def userDefinedImplicitNotFoundTypeMessage(using Context): Option[String] =
2839-
def recur(tp: Type): Option[String] = tp match
2847+
def recur(tp: Type, args: List[Type] = Nil): Option[String] = tp match
2848+
case tp: AppliedType =>
2849+
recur(tp.tycon, tp.args)
28402850
case tp: TypeRef =>
2841-
val sym = tp.symbol
2842-
userDefinedImplicitNotFoundTypeMessageFor(sym).orElse(recur(tp.info))
2851+
val typeParams = if tp.isLambdaSub then tp.hkTypeParams else tp.typeParams
2852+
userDefinedImplicitNotFoundTypeMessageFor(tp.symbol, typeParams, args)
2853+
.orElse(recur(tp.info))
28432854
case tp: ClassInfo =>
28442855
tp.baseClasses.iterator
2845-
.map(userDefinedImplicitNotFoundTypeMessageFor)
2856+
.map(userDefinedImplicitNotFoundTypeMessageFor(_))
28462857
.find(_.isDefined).flatten
28472858
case tp: TypeProxy =>
28482859
recur(tp.superType)

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,12 +266,11 @@ trait ParallelTesting extends RunnerOrchestration { self =>
266266
*/
267267
final def diffTest(testSource: TestSource, checkFile: JFile, actual: List[String], reporters: Seq[TestReporter], logger: LoggedRunnable) = {
268268
for (msg <- FileDiff.check(testSource.title, actual, checkFile.getPath)) {
269-
onFailure(testSource, reporters, logger, Some(msg))
270-
271269
if (updateCheckFiles) {
272270
FileDiff.dump(checkFile.toPath.toString, actual)
273271
echo("Updated checkfile: " + checkFile.getPath)
274272
} else {
273+
onFailure(testSource, reporters, logger, Some(msg))
275274
val outFile = checkFile.toPath.resolveSibling(s"${checkFile.toPath.getFileName}.out").toString
276275
FileDiff.dump(outFile, actual)
277276
echo(FileDiff.diffMessage(checkFile.getPath, outFile))

tests/neg/i7092.check

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- [E172] Type Error: tests/neg/i7092.scala:21:19 ----------------------------------------------------------------------
2+
21 | summon[F[String]] // error
3+
| ^
4+
| Not found for String
5+
-- [E172] Type Error: tests/neg/i7092.scala:22:19 ----------------------------------------------------------------------
6+
22 | summon[G[String]] // error
7+
| ^
8+
| Not found for String
9+
-- [E172] Type Error: tests/neg/i7092.scala:23:16 ----------------------------------------------------------------------
10+
23 | summon[H[Int]] // error
11+
| ^
12+
| Not found for Int, B
13+
-- [E172] Type Error: tests/neg/i7092.scala:24:19 ----------------------------------------------------------------------
14+
24 | summon[op.F[Int]] // error
15+
| ^
16+
| Could not find Int
17+
-- [E172] Type Error: tests/neg/i7092.scala:25:28 ----------------------------------------------------------------------
18+
25 | summon[String =!:= String] // error
19+
| ^
20+
| Cannot proof type inequality because types are equal: String =:= String

tests/neg/i7092.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import scala.annotation.implicitNotFound
2+
import scala.util.NotGiven
3+
4+
@implicitNotFound("Not found for ${A}")
5+
type F[A]
6+
7+
@implicitNotFound("Not found for ${A}")
8+
trait G[A]
9+
10+
@implicitNotFound("Not found for ${A}, ${B}")
11+
type H = [A] =>> [B] =>> (A, B)
12+
13+
object op:
14+
@implicitNotFound("Could not find ${A}")
15+
opaque type F[A] = A
16+
17+
@implicitNotFound("Cannot proof type inequality because types are equal: ${A} =:= ${B}")
18+
type =!:=[A, B] = NotGiven[A =:= B]
19+
20+
object Test:
21+
summon[F[String]] // error
22+
summon[G[String]] // error
23+
summon[H[Int]] // error
24+
summon[op.F[Int]] // error
25+
summon[String =!:= String] // error

0 commit comments

Comments
 (0)