Skip to content

Commit 8e0f98b

Browse files
committed
Improve robustness in the face of errors
1 parent 51607a4 commit 8e0f98b

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object Printers {
1818
val config: Printer = noPrinter
1919
val cyclicErrors: Printer = noPrinter
2020
val debug = noPrinter
21-
val derive = new Printer
21+
val derive = noPrinter
2222
val dottydoc: Printer = noPrinter
2323
val exhaustivity: Printer = noPrinter
2424
val gadts: Printer = noPrinter

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,23 @@ trait Deriving { this: Typer =>
3434
/** the children of `cls` ordered by textual occurrence */
3535
lazy val children = cls.children
3636

37+
private def shapeError(explanation: => String): Unit =
38+
ctx.error(i"cannot take shape of $cls\n$explanation", codePos)
39+
3740
/** The shape (of type Shape.Case) of a case given by `sym`. `sym` is either `cls`
3841
* itself, or a subclass of `cls`, or an instance of `cls`.
3942
*/
4043
private def caseShape(sym: Symbol): Type = {
4144
val (constr, elems) =
4245
sym match {
4346
case caseClass: ClassSymbol =>
44-
if (caseClass.is(Module))
47+
if (!caseClass.is(Case)) {
48+
shapeError(
49+
if (caseClass == cls) "it has anonymous or inaccessible subclasses"
50+
else i"its subclass $caseClass is not a case class")
51+
return NoType
52+
}
53+
else if (caseClass.is(Module))
4554
(caseClass.sourceModule.termRef, Nil)
4655
else caseClass.primaryConstructor.info match {
4756
case info: PolyType =>
@@ -72,7 +81,7 @@ trait Deriving { this: Typer =>
7281

7382
/** The shape of `cls` if `cls` is sealed */
7483
private def sealedShape: Type = {
75-
val cases = children.map(caseShape)
84+
val cases = children.map(caseShape).filter(_.exists)
7685
val casesShape = (cases :\ (defn.UnitType: Type))(defn.PairType.appliedTo(_, _))
7786
defn.ShapeCasesType.appliedTo(casesShape)
7887
}
@@ -84,7 +93,10 @@ trait Deriving { this: Typer =>
8493
lazy val shapeWithClassParams: Type = {
8594
if (cls.is(Case)) caseShape(cls)
8695
else if (cls.is(Sealed)) sealedShape
87-
else NoType
96+
else {
97+
shapeError(i"it is neither sealed nor a case class")
98+
defn.ShapeCasesType.appliedTo(defn.UnitType)
99+
}
88100
}.reporting(res => i"shape of $cls = $res", derive)
89101

90102
private def shapeOfType(tp: Type) = {
@@ -410,13 +422,11 @@ trait Deriving { this: Typer =>
410422
def syntheticDefs: List[Tree] = synthetics.map(syntheticDef).toList
411423
}
412424

413-
def finalize(stat: tpd.TypeDef): tpd.Tree =
414-
if (ctx.reporter.hasErrors) stat
415-
else {
416-
val templ @ Template(_, _, _, _) = stat.rhs
417-
tpd.cpy.TypeDef(stat)(
418-
rhs = tpd.cpy.Template(templ)(body = templ.body ++ new Finalizer().syntheticDefs))
419-
}
425+
def finalize(stat: tpd.TypeDef): tpd.Tree = {
426+
val templ @ Template(_, _, _, _) = stat.rhs
427+
tpd.cpy.TypeDef(stat)(
428+
rhs = tpd.cpy.Template(templ)(body = templ.body ++ new Finalizer().syntheticDefs))
429+
}
420430

421431
/** Synthesized instance for `Generic[<clsType>]` */
422432
def genericInstance(clsType: Type): tpd.Tree = {

tests/neg/deriving.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import reflect.Generic
2+
3+
sealed trait A derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses
4+
5+
object A {
6+
def f() = {
7+
println(new A {})
8+
println(new A {})
9+
}
10+
}
11+
12+
sealed trait B derives Generic // error: cannot take shape, its subclass class D is not a case class
13+
14+
class D(x: Int, y: String) extends B
15+
16+
17+
class E derives Generic // error: cannot take shape, it is neither sealed nor a case class
18+
19+
sealed trait F derives Generic // error: cannot take shape, it has anonymous or inaccessible subclasses
20+
21+
object G {
22+
def f() = {
23+
case class H() extends F
24+
}
25+
}

0 commit comments

Comments
 (0)