Skip to content

Commit 9622a3f

Browse files
committed
Nothing is a special bottom type; it is a subtype of every other type. The Scala compiler loves to infer Nothing as a generic type but that is almost always incorrect. Explicit type arguments should be used instead.
1 parent 8aeed88 commit 9622a3f

File tree

5 files changed

+54
-98
lines changed

5 files changed

+54
-98
lines changed

analyzer/src/main/scala/com/avsystem/commons/analyzer/AnalyzerPlugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ final class AnalyzerPlugin(val global: Global) extends Plugin { plugin =>
5656
new Any2StringAdd(global),
5757
new ThrowableObjects(global),
5858
new DiscardedMonixTask(global),
59-
new ThrownExceptionNotInFunction(global),
59+
new RequireExplicitNothing(global),
6060
new BadSingletonComponent(global),
6161
new ConstantDeclarations(global),
6262
new BasePackage(global),
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.avsystem.commons
2+
package analyzer
3+
4+
import scala.tools.nsc.Global
5+
6+
final class RequireExplicitNothing(g: Global) extends AnalyzerRule(g, "requireExplicitNothing") {
7+
8+
import global.*
9+
10+
private def wasInferred(t: TypeTree) = t.original == null
11+
12+
def analyze(unit: CompilationUnit): Unit = unit.body.foreach(analyzeTree {
13+
case tree@TypeTree() if tree.tpe <:< definitions.NothingTpe && wasInferred(tree) =>
14+
tree.tpe match {
15+
// Ignore existential types, they supposedly contain "any"
16+
case ExistentialType(_, _) =>
17+
18+
case _ => report(tree.pos, "Inferred type: Nothing")
19+
}
20+
})
21+
}

analyzer/src/main/scala/com/avsystem/commons/analyzer/ThrownExceptionNotInFunction.scala

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.avsystem.commons
2+
package analyzer
3+
4+
import org.scalatest.funsuite.AnyFunSuite
5+
6+
final class RequireExplicitNothingTest extends AnyFunSuite with AnalyzerTest {
7+
settings.pluginOptions.value ++= List("AVSystemAnalyzer:-discardedMonixTask")
8+
9+
test("simple") {
10+
assertErrors(4,
11+
//language=Scala
12+
"""|
13+
|object Test {
14+
| //not ok
15+
| val nook1 = throw new Exception
16+
| val nook2 = throw new Exception
17+
| def nook3 = throw new Exception
18+
| val nook4: List[Int] = List.empty //covariant
19+
|
20+
| //ok
21+
| val ok1: Nothing = throw new Exception
22+
| val ok2: Nothing = throw new Exception
23+
| def ok3: Nothing = throw new Exception
24+
| val ok4: List[Nothing] = List.empty[Nothing]
25+
| val ok5: List[Nothing] = Nil
26+
| val ok6: List[Int] = Nil
27+
| val ok7: Set[Int] = Set.empty //invariant
28+
|}
29+
|""".stripMargin
30+
)
31+
}
32+
}

analyzer/src/test/scala/com/avsystem/commons/analyzer/ThrownExceptionNotInFunctionTest.scala

Lines changed: 0 additions & 83 deletions
This file was deleted.

0 commit comments

Comments
 (0)