Skip to content

Commit fbe970e

Browse files
committed
Check for tasty error in template trees.
1 parent a5e029a commit fbe970e

File tree

13 files changed

+72
-10
lines changed

13 files changed

+72
-10
lines changed

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,20 @@ object Semantic:
448448
object TreeCache:
449449
class CacheData:
450450
private val emptyTrees = mutable.Set[ValOrDefDef]()
451+
private val emptyTemplates = mutable.Set[Template]()
452+
453+
def checkTemplateBodyValidity(tpl: Template, className: String)(using Context): Unit = {
454+
if (emptyTemplates.contains(tpl))
455+
throw new Exception("Error in body of " + className)
456+
457+
val errorCount = ctx.reporter.errorCount
458+
tpl.forceFields()
459+
460+
if (ctx.reporter.errorCount > errorCount)
461+
report.warning("Skipping the analysis of " + className + " due to an error reading the body of " + className + "'s TASTy.")
462+
emptyTemplates.add(tpl)
463+
throw new Exception("Error in body of " + className)
464+
}
451465

452466
extension (tree: ValOrDefDef)
453467
def getRhs(using Context): Tree =
@@ -465,7 +479,9 @@ object Semantic:
465479
if (emptyTrees.contains(tree)) EmptyTree
466480
else getTree
467481
end TreeCache
468-
482+
483+
inline def treeCache(using t: TreeCache.CacheData): TreeCache.CacheData = t
484+
469485
// ----- Operations on domains -----------------------------
470486
extension (a: Value)
471487
def join(b: Value): Value =
@@ -654,6 +670,7 @@ object Semantic:
654670
val methodType = atPhaseBeforeTransforms { meth.info.stripPoly }
655671
var allArgsHot = true
656672
val allParamTypes = methodType.paramInfoss.flatten.map(_.repeatedToSingle)
673+
assert(allParamTypes.size == args.size)
657674
val errors = allParamTypes.zip(args).flatMap { (info, arg) =>
658675
val tryReporter = Reporter.errorsIn { arg.promote }
659676
allArgsHot = allArgsHot && tryReporter.errors.isEmpty
@@ -1173,7 +1190,10 @@ object Semantic:
11731190
given Cache.Data()
11741191
given TreeCache.CacheData()
11751192
for classSym <- classes if isConcreteClass(classSym) && !classSym.isStaticObject do
1176-
checkClass(classSym)
1193+
try
1194+
checkClass(classSym)
1195+
catch
1196+
case e: Exception =>
11771197

11781198
// ----- Semantic definition --------------------------------
11791199
type ArgInfo = TraceValue[Value]
@@ -1520,6 +1540,8 @@ object Semantic:
15201540
* @param klass The class to which the template belongs.
15211541
*/
15221542
def init(tpl: Template, thisV: Ref, klass: ClassSymbol): Contextual[Value] = log("init " + klass.show, printer, (_: Value).show) {
1543+
treeCache.checkTemplateBodyValidity(tpl, klass.show)
1544+
15231545
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
15241546
vdef.name -> thisV.objekt.field(vdef.symbol)
15251547
}.toMap

compiler/src/dotty/tools/dotc/transform/init/Util.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ object Util:
4343
case Apply(fn, args) =>
4444
val argTps = fn.tpe.widen match
4545
case mt: MethodType => mt.paramInfos
46+
assert(args.size == argTps.size)
4647
val normArgs: List[Arg] = args.zip(argTps).map {
4748
case (arg, _: ExprType) => ByNameArg(arg)
4849
case (arg, _) => arg

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,46 @@ class CompilationTests {
278278
* compatible, but (b) and (c) are not. If (b) and (c) are compiled together, there should be
279279
* an error when reading the files' TASTy trees. */
280280
locally {
281-
val tastyErrorGroup = TestGroup("checkInit/tasty-error")
281+
val tastyErrorGroup = TestGroup("checkInit/tasty-error/val-or-defdef")
282282
val tastyErrorOptions = options.without("-Xfatal-warnings")
283283

284-
val a0Dir = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
285-
val a1Dir = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
286-
val b1Dir = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
284+
val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
285+
val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
286+
val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
287287

288288
val tests = List(
289-
compileFile("tests/init/tasty-error/v1/A.scala", tastyErrorOptions)(tastyErrorGroup),
290-
compileFile("tests/init/tasty-error/v1/B.scala", tastyErrorOptions.withClasspath(a1Dir))(tastyErrorGroup),
291-
compileFile("tests/init/tasty-error/v0/A.scala", tastyErrorOptions)(tastyErrorGroup),
289+
compileFile("tests/init/tasty-error/val-or-defdef/v1/A.scala", tastyErrorOptions)(tastyErrorGroup),
290+
compileFile("tests/init/tasty-error/val-or-defdef/v1/B.scala", tastyErrorOptions.withClasspath(classA1))(tastyErrorGroup),
291+
compileFile("tests/init/tasty-error/val-or-defdef/v0/A.scala", tastyErrorOptions)(tastyErrorGroup),
292292
).map(_.keepOutput.checkCompile())
293293

294-
compileFile("tests/init/tasty-error/Main.scala", tastyErrorOptions.withClasspath(a0Dir).withClasspath(b1Dir))(tastyErrorGroup).checkExpectedErrors()
294+
compileFile("tests/init/tasty-error/val-or-defdef/Main.scala", tastyErrorOptions.withClasspath(classA0).withClasspath(classB1))(tastyErrorGroup).checkExpectedErrors()
295+
296+
tests.foreach(_.delete())
297+
}
298+
299+
/* This tests for errors in the program's TASTy trees.
300+
* The test consists of four files: C, v1/A, v1/B, and v0/A. v1/A, v1/B, and v0/A all depend on C. v1/A and v1/B are
301+
* compatible, but v1/B and v0/A are not. If v1/B and v0/A are compiled together, there should be
302+
* an error when reading the files' TASTy trees. */
303+
locally {
304+
val tastyErrorGroup = TestGroup("checkInit/tasty-error/typedef")
305+
val tastyErrorOptions = options.without("-Xfatal-warnings")
306+
307+
val classC = defaultOutputDir + tastyErrorGroup + "/C/typedef/C"
308+
val classA0 = defaultOutputDir + tastyErrorGroup + "/A/v0/A"
309+
val classA1 = defaultOutputDir + tastyErrorGroup + "/A/v1/A"
310+
val classB1 = defaultOutputDir + tastyErrorGroup + "/B/v1/B"
311+
312+
val tests = List(
313+
compileFile("tests/init/tasty-error/typedef/C.scala", tastyErrorOptions)(tastyErrorGroup),
314+
compileFile("tests/init/tasty-error/typedef/v1/A.scala", tastyErrorOptions.withClasspath(classC))(tastyErrorGroup),
315+
compileFile("tests/init/tasty-error/typedef/v1/B.scala", tastyErrorOptions.withClasspath(classC).withClasspath(classA1))(tastyErrorGroup),
316+
compileFile("tests/init/tasty-error/typedef/v0/A.scala", tastyErrorOptions.withClasspath(classC))(tastyErrorGroup),
317+
).map(_.keepOutput.checkCompile())
318+
319+
compileFile("tests/init/tasty-error/typedef/Main.scala", tastyErrorOptions.withClasspath(classC).withClasspath(classA0).withClasspath(classB1))(tastyErrorGroup).checkExpectedErrors()
320+
compileFile("tests/init/tasty-error/typedef/DependOnB.scala", tastyErrorOptions.withClasspath(classC).withClasspath(classA0).withClasspath(classB1))(tastyErrorGroup).checkCompile()
295321

296322
tests.foreach(_.delete())
297323
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class C
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class DependOnB extends B{}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class A(c1: C) {
2+
def fail(a: Int, b: Int): Int = a
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class A(c1: C, c2: C) {
2+
def fail(a: Int, b: Int): Int = a
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class B extends C{
2+
new A(this, this).fail(0,0)
3+
val x = 5
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Main extends B{} // anypos-error

0 commit comments

Comments
 (0)