Skip to content

Commit 53b4587

Browse files
Renamer: Add infrastructure for Checking Uniqueness of Generated Names (#941)
After #938, the `RenamerTests` do not check that the names are actually unique. This adds assertions checking that every `Id` only occurs in one definition-like construct. (note that 4cf2371 is intentionally wrong to show it failing on shadowing :) )
1 parent c86c0c6 commit 53b4587

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

effekt/jvm/src/test/scala/effekt/core/RenamerTests.scala

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package effekt.core
22

3+
import scala.collection.mutable
4+
35
/**
46
* This is testing the main/core.Renamer using the test/core.TestRenamer.
57
*/
@@ -17,6 +19,59 @@ class RenamerTests extends CoreTests {
1719
assertAlphaEquivalent(obtained, pInput, clue)
1820
}
1921

22+
def assertDefsUnique(in: ModuleDecl,
23+
clue: => Any = "Duplicate definition") = {
24+
val seen = mutable.HashSet.empty[Id]
25+
26+
def isFresh(id: Id): Unit = {
27+
assert(!seen.contains(id), clue)
28+
seen.add(id)
29+
}
30+
31+
object check extends Tree.Query[Unit, Unit] {
32+
override def empty = ()
33+
34+
override def combine = (_, _) => ()
35+
36+
override def visit[T](t: T)(visitor: Unit ?=> T => Unit)(using Unit): Unit = {
37+
visitor(t)
38+
t match {
39+
case m: ModuleDecl =>
40+
m.definitions.foreach { d => isFresh(d.id) }
41+
case d: Def => isFresh(d.id)
42+
case v: Val => isFresh(v.id)
43+
case l: Let => isFresh(l.id)
44+
case d: Declaration => isFresh(d.id)
45+
case e: Extern.Def =>
46+
isFresh(e.id)
47+
e.tparams.foreach(isFresh);
48+
e.vparams.foreach { p => isFresh(p.id) }
49+
e.bparams.foreach { p => isFresh(p.id) };
50+
e.cparams.foreach { p => isFresh(p) }
51+
case b: BlockLit =>
52+
b.tparams.foreach(isFresh);
53+
b.cparams.foreach(isFresh)
54+
b.vparams.foreach { p => isFresh(p.id) };
55+
b.bparams.foreach { p => isFresh(p.id) }
56+
case i: Implementation =>
57+
i.operations.foreach { o =>
58+
o.vparams.foreach { p => isFresh(p.id) }; o.bparams.foreach { p => isFresh(p.id) }
59+
}
60+
case _ => ()
61+
}
62+
}
63+
}
64+
check.query(in)(using ())
65+
}
66+
def assertRenamingMakesDefsUnique(input: String,
67+
clue: => Any = "Duplicate definition",
68+
names: Names = Names(defaultNames))(using munit.Location) = {
69+
val pInput = parse(input, "input", names)
70+
val renamer = new Renamer(names, "renamed")
71+
val obtained = renamer(pInput)
72+
assertDefsUnique(obtained, clue)
73+
}
74+
2075
test("No bound local variables"){
2176
val code =
2277
"""module main
@@ -26,6 +81,7 @@ class RenamerTests extends CoreTests {
2681
|}
2782
|""".stripMargin
2883
assertRenamingPreservesAlpha(code)
84+
assertRenamingMakesDefsUnique(code)
2985
}
3086

3187
test("val binding"){
@@ -38,6 +94,7 @@ class RenamerTests extends CoreTests {
3894
|}
3995
|""".stripMargin
4096
assertRenamingPreservesAlpha(code)
97+
assertRenamingMakesDefsUnique(code)
4198
}
4299

43100
test("var binding"){
@@ -50,6 +107,7 @@ class RenamerTests extends CoreTests {
50107
|}
51108
|""".stripMargin
52109
assertRenamingPreservesAlpha(code)
110+
assertRenamingMakesDefsUnique(code)
53111
}
54112

55113
test("function (value) parameters"){
@@ -61,6 +119,7 @@ class RenamerTests extends CoreTests {
61119
|}
62120
|""".stripMargin
63121
assertRenamingPreservesAlpha(code)
122+
assertRenamingMakesDefsUnique(code)
64123
}
65124

66125
test("match clauses"){
@@ -75,6 +134,7 @@ class RenamerTests extends CoreTests {
75134
|}
76135
|""".stripMargin
77136
assertRenamingPreservesAlpha(code)
137+
assertRenamingMakesDefsUnique(code)
78138
}
79139

80140
test("type parameters"){
@@ -86,6 +146,7 @@ class RenamerTests extends CoreTests {
86146
|}
87147
|""".stripMargin
88148
assertRenamingPreservesAlpha(code)
149+
assertRenamingMakesDefsUnique(code)
89150
}
90151

91152
test("pseudo recursive"){
@@ -100,6 +161,7 @@ class RenamerTests extends CoreTests {
100161
| }
101162
|""".stripMargin
102163
assertRenamingPreservesAlpha(code)
164+
assertRenamingMakesDefsUnique(code)
103165
}
104166
test("shadowing let bindings"){
105167
val code =
@@ -112,5 +174,6 @@ class RenamerTests extends CoreTests {
112174
| }
113175
|""".stripMargin
114176
assertRenamingPreservesAlpha(code)
177+
assertRenamingMakesDefsUnique(code)
115178
}
116179
}

effekt/shared/src/main/scala/effekt/core/Tree.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ object Tree {
432432
case (id, lit) => query(lit)
433433
}
434434
def query(b: ExternBody)(using Ctx): Res = structuralQuery(b, externBody)
435+
def query(m: ModuleDecl)(using Ctx) = structuralQuery(m, PartialFunction.empty)
435436
}
436437

437438
class Rewrite extends Structural {

0 commit comments

Comments
 (0)