From 6fd24716ac9f8c19b2faa649c7ba32e96d529485 Mon Sep 17 00:00:00 2001
From: Daisy Li
Date: Mon, 24 Mar 2025 22:28:18 -0400
Subject: [PATCH 1/2] Report warning for argument parameter number mismatch.
---
.../tools/dotc/transform/init/Semantic.scala | 23 ++++++++++-
.../tools/dotc/transform/init/Util.scala | 5 +++
.../dotty/tools/dotc/CompilationTests.scala | 41 +++++++++++++++----
tests/init/tasty-error/typedef/C.scala | 1 +
tests/init/tasty-error/typedef/Main.scala | 2 +
tests/init/tasty-error/typedef/v0/A.scala | 3 ++
tests/init/tasty-error/typedef/v1/A.scala | 3 ++
tests/init/tasty-error/typedef/v1/B.scala | 4 ++
.../{ => val-or-defdef}/Main.scala | 0
.../{ => val-or-defdef}/v0/A.scala | 0
.../{ => val-or-defdef}/v1/A.scala | 0
.../{ => val-or-defdef}/v1/B.scala | 0
12 files changed, 73 insertions(+), 9 deletions(-)
create mode 100644 tests/init/tasty-error/typedef/C.scala
create mode 100644 tests/init/tasty-error/typedef/Main.scala
create mode 100644 tests/init/tasty-error/typedef/v0/A.scala
create mode 100644 tests/init/tasty-error/typedef/v1/A.scala
create mode 100644 tests/init/tasty-error/typedef/v1/B.scala
rename tests/init/tasty-error/{ => val-or-defdef}/Main.scala (100%)
rename tests/init/tasty-error/{ => val-or-defdef}/v0/A.scala (100%)
rename tests/init/tasty-error/{ => val-or-defdef}/v1/A.scala (100%)
rename tests/init/tasty-error/{ => val-or-defdef}/v1/B.scala (100%)
diff --git a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
index 5d9b4f0e5ce0..a9115251e14f 100644
--- a/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
+++ b/compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
@@ -448,6 +448,18 @@ object Semantic:
object TreeCache:
class CacheData:
private val emptyTrees = mutable.Set[ValOrDefDef]()
+ private val templatesToSkip = mutable.Set[Template]()
+
+ def checkTemplateBodyValidity(tpl: Template, className: String)(using Context): Unit =
+ if (templatesToSkip.contains(tpl))
+ throw new TastyTreeException(className)
+
+ val errorCount = ctx.reporter.errorCount
+ tpl.forceFields()
+
+ if (ctx.reporter.errorCount > errorCount)
+ templatesToSkip.add(tpl)
+ throw new TastyTreeException(className)
extension (tree: ValOrDefDef)
def getRhs(using Context): Tree =
@@ -466,6 +478,8 @@ object Semantic:
else getTree
end TreeCache
+ inline def treeCache(using t: TreeCache.CacheData): TreeCache.CacheData = t
+
// ----- Operations on domains -----------------------------
extension (a: Value)
def join(b: Value): Value =
@@ -645,6 +659,8 @@ object Semantic:
val methodType = atPhaseBeforeTransforms { meth.info.stripPoly }
var allArgsHot = true
val allParamTypes = methodType.paramInfoss.flatten.map(_.repeatedToSingle)
+ if(allParamTypes.size != args.size)
+ report.warning("[Internal error] Number of parameters do not match number of arguments in " + meth.name)
val errors = allParamTypes.zip(args).flatMap { (info, arg) =>
val tryReporter = Reporter.errorsIn { arg.promote }
allArgsHot = allArgsHot && tryReporter.errors.isEmpty
@@ -1164,7 +1180,10 @@ object Semantic:
given Cache.Data()
given TreeCache.CacheData()
for classSym <- classes if isConcreteClass(classSym) do
- checkClass(classSym)
+ try
+ checkClass(classSym)
+ catch
+ case TastyTreeException(className) => report.warning("Skipping the analysis of " + classSym.show + " due to an error reading the body of " + className + "'s TASTy.")
// ----- Semantic definition --------------------------------
type ArgInfo = TraceValue[Value]
@@ -1498,6 +1517,8 @@ object Semantic:
* @param klass The class to which the template belongs.
*/
def init(tpl: Template, thisV: Ref, klass: ClassSymbol): Contextual[Value] = log("init " + klass.show, printer, (_: Value).show) {
+ treeCache.checkTemplateBodyValidity(tpl, klass.show)
+
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
vdef.name -> thisV.objekt.field(vdef.symbol)
}.toMap
diff --git a/compiler/src/dotty/tools/dotc/transform/init/Util.scala b/compiler/src/dotty/tools/dotc/transform/init/Util.scala
index ba2216504aef..a4741e276188 100644
--- a/compiler/src/dotty/tools/dotc/transform/init/Util.scala
+++ b/compiler/src/dotty/tools/dotc/transform/init/Util.scala
@@ -15,6 +15,9 @@ import config.Printers.init as printer
import Trace.*
object Util:
+ /** Exception used for errors encountered when reading TASTy. */
+ case class TastyTreeException(msg: String) extends RuntimeException(msg)
+
/** Utility definition used for better error-reporting of argument errors */
case class TraceValue[T](value: T, trace: Trace)
@@ -39,6 +42,8 @@ object Util:
case Apply(fn, args) =>
val argTps = fn.tpe.widen match
case mt: MethodType => mt.paramInfos
+ if (args.size != argTps.size)
+ report.warning("[Internal error] Number of arguments do not match number of argument types in " + tree.symbol.name)
val normArgs: List[Arg] = args.zip(argTps).map {
case (arg, _: ExprType) => ByNameArg(arg)
case (arg, _) => arg
diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala
index e9562b016a74..9571e80d5ccd 100644
--- a/compiler/test/dotty/tools/dotc/CompilationTests.scala
+++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala
@@ -241,20 +241,45 @@ class CompilationTests {
* compatible, but (b) and (c) are not. If (b) and (c) are compiled together, there should be
* an error when reading the files' TASTy trees. */
locally {
- val tastyErrorGroup = TestGroup("checkInit/tasty-error")
+ val tastyErrorGroup = TestGroup("checkInit/tasty-error/val-or-defdef")
val tastyErrorOptions = options.without("-Xfatal-warnings")
- val a0Dir = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
- val a1Dir = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
- val b1Dir = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
+ val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
+ val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
+ val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
val tests = List(
- compileFile("tests/init/tasty-error/v1/A.scala", tastyErrorOptions)(tastyErrorGroup),
- compileFile("tests/init/tasty-error/v1/B.scala", tastyErrorOptions.withClasspath(a1Dir))(tastyErrorGroup),
- compileFile("tests/init/tasty-error/v0/A.scala", tastyErrorOptions)(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/val-or-defdef/v1/A.scala", tastyErrorOptions)(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/val-or-defdef/v1/B.scala", tastyErrorOptions.withClasspath(classA1))(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/val-or-defdef/v0/A.scala", tastyErrorOptions)(tastyErrorGroup),
).map(_.keepOutput.checkCompile())
- compileFile("tests/init/tasty-error/Main.scala", tastyErrorOptions.withClasspath(a0Dir).withClasspath(b1Dir))(tastyErrorGroup).checkExpectedErrors()
+ compileFile("tests/init/tasty-error/val-or-defdef/Main.scala", tastyErrorOptions.withClasspath(classA0).withClasspath(classB1))(tastyErrorGroup).checkExpectedErrors()
+
+ tests.foreach(_.delete())
+ }
+
+ /* This tests for errors in the program's TASTy trees.
+ * The test consists of five files: Main, C, v1/A, v1/B, and v0/A. The files v1/A, v1/B, and v0/A all depend on C. v1/A and v1/B are
+ * compatible, but v1/B and v0/A are not. If v1/B and v0/A are compiled together, there should be
+ * an error when reading the files' TASTy trees. This fact is demonstrated by the compilation of Main. */
+ locally {
+ val tastyErrorGroup = TestGroup("checkInit/tasty-error/typedef")
+ val tastyErrorOptions = options.without("-Xfatal-warnings").without("-Ycheck:all")
+
+ val classC = defaultOutputDir + tastyErrorGroup + "/C/typedef/C"
+ val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
+ val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
+ val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
+
+ val tests = List(
+ compileFile("tests/init/tasty-error/typedef/C.scala", tastyErrorOptions)(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/typedef/v1/A.scala", tastyErrorOptions.withClasspath(classC))(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/typedef/v1/B.scala", tastyErrorOptions.withClasspath(classC).withClasspath(classA1))(tastyErrorGroup),
+ compileFile("tests/init/tasty-error/typedef/v0/A.scala", tastyErrorOptions.withClasspath(classC))(tastyErrorGroup),
+ ).map(_.keepOutput.checkCompile())
+
+ compileFile("tests/init/tasty-error/typedef/Main.scala", tastyErrorOptions.withClasspath(classC).withClasspath(classA0).withClasspath(classB1))(tastyErrorGroup).checkExpectedErrors()
tests.foreach(_.delete())
}
diff --git a/tests/init/tasty-error/typedef/C.scala b/tests/init/tasty-error/typedef/C.scala
new file mode 100644
index 000000000000..9dccdd5e5954
--- /dev/null
+++ b/tests/init/tasty-error/typedef/C.scala
@@ -0,0 +1 @@
+class C
\ No newline at end of file
diff --git a/tests/init/tasty-error/typedef/Main.scala b/tests/init/tasty-error/typedef/Main.scala
new file mode 100644
index 000000000000..232a7c34c4e1
--- /dev/null
+++ b/tests/init/tasty-error/typedef/Main.scala
@@ -0,0 +1,2 @@
+class Main extends B{} // anypos-error
+class ExtendsB extends B{}
\ No newline at end of file
diff --git a/tests/init/tasty-error/typedef/v0/A.scala b/tests/init/tasty-error/typedef/v0/A.scala
new file mode 100644
index 000000000000..9c86f47e2c77
--- /dev/null
+++ b/tests/init/tasty-error/typedef/v0/A.scala
@@ -0,0 +1,3 @@
+class A(c1: C) {
+ def fail(a: Int, b: Int): Int = a
+}
diff --git a/tests/init/tasty-error/typedef/v1/A.scala b/tests/init/tasty-error/typedef/v1/A.scala
new file mode 100644
index 000000000000..a79930e5dd30
--- /dev/null
+++ b/tests/init/tasty-error/typedef/v1/A.scala
@@ -0,0 +1,3 @@
+class A(c1: C, c2: C) {
+ def fail(a: Int, b: Int): Int = a
+}
diff --git a/tests/init/tasty-error/typedef/v1/B.scala b/tests/init/tasty-error/typedef/v1/B.scala
new file mode 100644
index 000000000000..801efcb5fdf0
--- /dev/null
+++ b/tests/init/tasty-error/typedef/v1/B.scala
@@ -0,0 +1,4 @@
+class B extends C{
+ new A(this, this).fail(0,0)
+ val x = 5
+}
\ No newline at end of file
diff --git a/tests/init/tasty-error/Main.scala b/tests/init/tasty-error/val-or-defdef/Main.scala
similarity index 100%
rename from tests/init/tasty-error/Main.scala
rename to tests/init/tasty-error/val-or-defdef/Main.scala
diff --git a/tests/init/tasty-error/v0/A.scala b/tests/init/tasty-error/val-or-defdef/v0/A.scala
similarity index 100%
rename from tests/init/tasty-error/v0/A.scala
rename to tests/init/tasty-error/val-or-defdef/v0/A.scala
diff --git a/tests/init/tasty-error/v1/A.scala b/tests/init/tasty-error/val-or-defdef/v1/A.scala
similarity index 100%
rename from tests/init/tasty-error/v1/A.scala
rename to tests/init/tasty-error/val-or-defdef/v1/A.scala
diff --git a/tests/init/tasty-error/v1/B.scala b/tests/init/tasty-error/val-or-defdef/v1/B.scala
similarity index 100%
rename from tests/init/tasty-error/v1/B.scala
rename to tests/init/tasty-error/val-or-defdef/v1/B.scala
From eeaa5607719b97dec14bd2c62e052cff22e7476b Mon Sep 17 00:00:00 2001
From: Tomasz Godzik
Date: Mon, 28 Apr 2025 11:00:27 +0200
Subject: [PATCH 2/2] Report warning for argument parameter number mismatch.
[Cherry-picked 884436fd2c641cd32c5d68b06dc5c13fb1dcc1d3][modified]