Skip to content

Commit e4ef18d

Browse files
committed
Fail if deferred given impl is recursive
1 parent 66b14d3 commit e4ef18d

File tree

8 files changed

+93
-2
lines changed

8 files changed

+93
-2
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3277,7 +3277,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
32773277
val superCls = cls.superClass
32783278
superCls.exists && superCls.asClass.baseClasses.contains(m.symbol.owner)
32793279

3280-
def givenImpl(mbr: TermRef): ValDef =
3280+
def givenImpl(mbr: TermRef): ValDef | EmptyTree.type =
32813281
val dcl = mbr.symbol
32823282
val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
32833283
val constr = cls.primaryConstructor
@@ -3315,7 +3315,16 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
33153315
cpy.Select(id)(This(cls), id.name)
33163316
case _ =>
33173317
super.transform(tree)
3318-
ValDef(impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
3318+
3319+
rhs.tpe match
3320+
case tp: NamedType if tp.prefix.typeSymbol == cls && tp.name == mbr.name && !tp.typeSymbol.is(Method) =>
3321+
report.error(
3322+
em"""Inferred implementation of the deferred ${dcl.showLocated} is self-recursive.
3323+
|An implementing given needs to be written explicitly.""",
3324+
cdef.srcPos)
3325+
EmptyTree
3326+
case _ =>
3327+
ValDef(impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
33193328
end givenImpl
33203329

33213330
val givenImpls =

tests/neg/i22589.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Error: tests/neg/i22589.scala:15:7 ----------------------------------------------------------------------------------
2+
15 |object Person extends CompanionEssentials[Person]: // error
3+
|^
4+
|Inferred implementation of the deferred given instance given_MyCodec_E in trait CompanionEssentials is self-recursive.
5+
|An implementing given needs to be written explicitly.
6+
16 | //override final lazy given given_MyCodec_E: MyCodec[Person] = Person.given_MyCodec_E
7+
17 | override def toString = ""

tests/neg/i22589.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
//> using options -Wsafe-init -Ysafe-init-global
3+
4+
import scala.compiletime.deferred
5+
6+
trait MyCodec[E]
7+
8+
object auto:
9+
trait CompanionEssentials[E]:
10+
given MyCodec[E] = deferred
11+
12+
import auto.CompanionEssentials
13+
14+
case class Person(name: String, age: Int)
15+
object Person extends CompanionEssentials[Person]: // error
16+
//override final lazy given given_MyCodec_E: MyCodec[Person] = Person.given_MyCodec_E
17+
override def toString = ""

tests/neg/i22589b.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Error: tests/neg/i22589b.scala:13:7 ---------------------------------------------------------------------------------
2+
13 |object Person extends CompanionEssentials[Person]: // error
3+
|^
4+
|Inferred implementation of the deferred given instance myc in trait CompanionEssentials is self-recursive.
5+
|An implementing given needs to be written explicitly.
6+
14 | given String = "hw"
7+
15 | given myc(using String): MyCodec[Person] = new MyCodec[Person] {}
8+
16 | override def toString = ""

tests/neg/i22589b.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
import scala.compiletime.deferred
3+
4+
trait MyCodec[E]
5+
6+
object auto:
7+
trait CompanionEssentials[E]:
8+
given myc: MyCodec[E] = deferred
9+
10+
import auto.CompanionEssentials
11+
12+
case class Person(name: String, age: Int)
13+
object Person extends CompanionEssentials[Person]: // error
14+
given String = "hw"
15+
given myc(using String): MyCodec[Person] = new MyCodec[Person] {}
16+
override def toString = ""

tests/neg/i22589c.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Error: tests/neg/i22589c.scala:8:7 ----------------------------------------------------------------------------------
2+
8 |object A extends Base[A.P] { // error
3+
|^
4+
|Inferred implementation of the deferred given instance given_TC_T in trait Base is self-recursive.
5+
|An implementing given needs to be written explicitly.
6+
9 | case class P()
7+
10 |}

tests/neg/i22589c.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
trait TC[T]
3+
4+
trait Base[T] {
5+
given TC[T] = scala.compiletime.deferred
6+
}
7+
8+
object A extends Base[A.P] { // error
9+
case class P()
10+
}

tests/pos/i22589.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
import scala.compiletime.deferred
3+
4+
trait MyCodec[E]
5+
6+
object auto:
7+
trait CompanionEssentials[E]:
8+
//given [E] => MyCodec[E] = deferred
9+
given MyCodec[E] = deferred
10+
11+
import auto.CompanionEssentials
12+
13+
case class Person(name: String, age: Int)
14+
object Person extends CompanionEssentials[Person]:
15+
//given something: [E] => MyCodec[E] = new MyCodec[E] {}
16+
given something: MyCodec[Person] = new MyCodec[Person] {}
17+
override def toString = ""

0 commit comments

Comments
 (0)