Skip to content

Commit

Permalink
[Issue 15987] Nicer error message in case a derived method has an e…
Browse files Browse the repository at this point in the history
…xplicit term param (#21332)
  • Loading branch information
dwijnand authored Sep 3, 2024
2 parents 5730f91 + ffac87d commit 78561ce
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 2 deletions.
15 changes: 13 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Deriving.scala
Original file line number Diff line number Diff line change
Expand Up @@ -292,10 +292,21 @@ trait Deriving {
val companion = companionRef(resultType)
val module = untpd.ref(companion).withSpan(sym.span)
val rhs = untpd.Select(module, nme.derived)
if companion.termSymbol.exists then typed(rhs, resultType)
else errorTree(rhs, em"$resultType cannot be derived since ${resultType.typeSymbol} has no companion object")
val derivedMember = companion.member(nme.derived)

if !companion.termSymbol.exists then
errorTree(rhs, em"$resultType cannot be derived since ${resultType.typeSymbol} has no companion object")
else if hasExplicitParams(derivedMember.symbol) then
errorTree(rhs, em"""derived instance $resultType failed to generate:
|method `derived` from object ${module} takes explicit term parameters""")
else
typed(rhs, resultType)
end typeclassInstance

// checks whether any of the params of 'sym' is explicit
def hasExplicitParams(sym: Symbol) =
!sym.paramSymss.flatten.forall(sym => sym.isType || sym.is(Flags.Given) || sym.is(Flags.Implicit))

def syntheticDef(sym: Symbol): Tree = inContext(ctx.fresh.setOwner(sym).setNewScope) {
if sym.is(Method) then tpd.DefDef(sym.asTerm, typeclassInstance(sym))
else tpd.ValDef(sym.asTerm, typeclassInstance(sym)(Nil))
Expand Down
5 changes: 5 additions & 0 deletions tests/neg/i15987.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- Error: tests/neg/i15987.scala:26:40 ---------------------------------------------------------------------------------
26 |case class Person(name: String) derives ShowWithExplicit, // error
| ^
| derived instance ShowWithExplicit[Person] failed to generate:
| method `derived` from object ShowWithExplicit takes explicit term parameters
30 changes: 30 additions & 0 deletions tests/neg/i15987.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
trait ShowWithExplicit[A]

object ShowWithExplicit:
def derived[A, B](explicit: String)(using DummyImplicit)(implicit dummy: DummyImplicit): ShowWithExplicit[A] = ???

trait ShowUsingAndImplicit[A]

object ShowUsingAndImplicit:
def derived[A, B](using DummyImplicit)(implicit dummy: DummyImplicit): ShowUsingAndImplicit[A] = ???

trait ShowUsing[A]

object ShowUsing:
def derived[A](using DummyImplicit): ShowUsing[A] = ???

trait ShowImplicit[A]

object ShowImplicit:
def derived[A](implicit ev: DummyImplicit): ShowImplicit[A] = ???

trait ShowContra[-A]

object ShowContra:
val derived: ShowContra[Any] = ???

case class Person(name: String) derives ShowWithExplicit, // error
ShowUsingAndImplicit,
ShowUsing,
ShowImplicit,
ShowContra

0 comments on commit 78561ce

Please sign in to comment.