Skip to content

Commit

Permalink
reject derived with explicit term params
Browse files Browse the repository at this point in the history
  • Loading branch information
arainko committed Aug 4, 2024
1 parent 7f5e4ce commit f43fe1f
Show file tree
Hide file tree
Showing 3 changed files with 49 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
4 changes: 4 additions & 0 deletions tests/neg/i15987/DerivedIssue.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Error: tests/neg/7722.scala:2:40 ------------------------------------------------------------------------------------
2 | @scala.annotation.targetName("E") def this() = this(3) // error
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| @targetName annotation may not be used on a constructor
32 changes: 32 additions & 0 deletions tests/neg/i15987/DerivedIssue.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import scala.language.experimental.clauseInterleaving

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 f43fe1f

Please sign in to comment.