Skip to content

Commit a2c89fb

Browse files
authored
Propagate implicit search errors from implicit macros (#16840)
Fixes partially #16835
2 parents 3d251d6 + 1f5a990 commit a2c89fb

File tree

5 files changed

+50
-4
lines changed

5 files changed

+50
-4
lines changed

compiler/src/dotty/tools/dotc/transform/Splicer.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ object Splicer {
119119
sym.exists && !sym.is(Package)
120120
&& sym.owner.ownersIterator.exists(x =>
121121
x == expansionOwner || // symbol was generated within this macro expansion
122-
x.is(Macro, butNot = Method) && x.name == nme.MACROkw // symbol was generated within another macro expansion
122+
isMacroOwner(x) // symbol was generated within another macro expansion
123123
)
124124
&& !locals.contains(sym) // symbol is not in current scope
125125
}.traverse(tree)
@@ -222,6 +222,14 @@ object Splicer {
222222
checkIfValidStaticCall(tree)(using Set.empty)
223223
}
224224

225+
/** Is this the dummy owner of a macro expansion */
226+
def isMacroOwner(sym: Symbol)(using Context): Boolean =
227+
sym.is(Macro, butNot = Method) && sym.name == nme.MACROkw
228+
229+
/** Is this the dummy owner of a macro expansion */
230+
def inMacroExpansion(using Context) =
231+
ctx.owner.ownersIterator.exists(isMacroOwner)
232+
225233
/** Tree interpreter that evaluates the tree.
226234
* Interpreter is assumed to start at quotation level -1.
227235
*/

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import Feature.migrateTo3
3131
import config.Printers.{implicits, implicitsDetailed}
3232
import collection.mutable
3333
import reporting._
34+
import transform.Splicer
3435
import annotation.tailrec
3536

3637
import scala.annotation.internal.sharable
@@ -567,6 +568,12 @@ object Implicits:
567568

568569
def msg(using Context) = em"Failed to synthesize an instance of type ${clarify(expectedType)}:${formatReasons}"
569570

571+
class MacroErrorsFailure(errors: List[Diagnostic.Error],
572+
val expectedType: Type,
573+
val argument: Tree) extends SearchFailureType {
574+
def msg(using Context): Message =
575+
em"${errors.map(_.msg).mkString("\n")}"
576+
}
570577
end Implicits
571578

572579
import Implicits._
@@ -1157,19 +1164,22 @@ trait Implicits:
11571164
if ctx.reporter.hasErrors
11581165
|| !cand.ref.symbol.isAccessibleFrom(cand.ref.prefix)
11591166
then
1160-
ctx.reporter.removeBufferedMessages
1161-
adapted.tpe match {
1167+
val res = adapted.tpe match {
11621168
case _: SearchFailureType => SearchFailure(adapted)
11631169
case error: PreviousErrorType if !adapted.symbol.isAccessibleFrom(cand.ref.prefix) =>
11641170
SearchFailure(adapted.withType(new NestedFailure(error.msg, pt)))
1165-
case _ =>
1171+
case tpe =>
11661172
// Special case for `$conforms` and `<:<.refl`. Showing them to the users brings
11671173
// no value, so we instead report a `NoMatchingImplicitsFailure`
11681174
if (adapted.symbol == defn.Predef_conforms || adapted.symbol == defn.SubType_refl)
11691175
NoMatchingImplicitsFailure
1176+
else if Splicer.inMacroExpansion && tpe <:< pt then
1177+
SearchFailure(adapted.withType(new MacroErrorsFailure(ctx.reporter.allErrors.reverse, pt, argument)))
11701178
else
11711179
SearchFailure(adapted.withType(new MismatchedImplicit(ref, pt, argument)))
11721180
}
1181+
ctx.reporter.removeBufferedMessages
1182+
res
11731183
else
11741184
SearchSuccess(adapted, ref, cand.level, cand.isExtension)(ctx.typerState, ctx.gadt)
11751185
}

tests/neg-macros/i16835.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
-- Error: tests/neg-macros/i16835/Test_2.scala:1:17 --------------------------------------------------------------------
3+
1 |def test: Unit = foo // error
4+
| ^^^
5+
| my error
6+
| my second error

tests/neg-macros/i16835/Macro_1.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import scala.quoted.*
2+
3+
class Bar
4+
5+
inline def foo: Unit = ${ fooExpr }
6+
7+
def fooExpr(using Quotes): Expr[Unit] =
8+
import quotes.reflect.*
9+
Implicits.search(TypeRepr.of[Bar]) match
10+
case res: ImplicitSearchSuccess => '{}
11+
case failure: ImplicitSearchFailure =>
12+
report.errorAndAbort(failure.explanation)
13+
14+
15+
inline given bar: Bar = ${ barExpr }
16+
17+
def barExpr(using Quotes): Expr[Bar] =
18+
import quotes.reflect.*
19+
report.error(s"my error")
20+
report.error(s"my second error")
21+
'{ new Bar }

tests/neg-macros/i16835/Test_2.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def test: Unit = foo // error

0 commit comments

Comments
 (0)