// SPDX-License-Identifier: Apache-2.0 package firrtlTests import firrtl.RenameMap import firrtl.renamemap.MutableRenameMap import firrtl.RenameMap.IllegalRenameException import firrtl.annotations._ import firrtl.annotations.TargetToken.{Instance, OfModule} import firrtl.analyses.InstanceKeyGraph import firrtl.testutils._ class MutableRenameMapSpec extends FirrtlFlatSpec { val cir = CircuitTarget("Top") val cir2 = CircuitTarget("Pot") val cir3 = CircuitTarget("Cir3") val modA = cir.module("A") val modA2 = cir2.module("A") val modB = cir.module("B") val foo = modA.ref("foo") val foo2 = modA2.ref("foo") val bar = modA.ref("bar") val fizz = modA.ref("fizz") val fooB = modB.ref("foo") val barB = modB.ref("bar") val tmb = cir.module("Top").instOf("mid", "Middle").instOf("bot", "Bottom") val tm2b = cir.module("Top").instOf("mid", "Middle2").instOf("bot", "Bottom") val middle = cir.module("Middle") val middle2 = cir.module("Middle2") behavior.of("RenameMap") it should "return None if it does not rename something" in { val renames = MutableRenameMap() renames.get(modA) should be(None) renames.get(foo) should be(None) } it should "return a Seq of renamed things if it does rename something" in { val renames = MutableRenameMap() renames.record(foo, bar) renames.get(foo) should be(Some(Seq(bar))) } it should "allow something to be renamed to multiple things" in { val renames = MutableRenameMap() renames.record(foo, bar) renames.record(foo, fizz) renames.get(foo) should be(Some(Seq(bar, fizz))) } it should "allow something to be renamed to nothing (ie. deleted)" in { val renames = MutableRenameMap() renames.record(foo, Seq()) renames.get(foo) should be(Some(Seq())) } it should "return None if something is renamed to itself" in { val renames = MutableRenameMap() renames.record(foo, foo) renames.get(foo) should be(None) } it should "allow targets to change module" in { val renames = MutableRenameMap() renames.record(foo, fooB) renames.get(foo) should be(Some(Seq(fooB))) } it should "rename targets if their module is renamed" in { val renames = MutableRenameMap() renames.record(modA, modB) renames.get(foo) should be(Some(Seq(fooB))) renames.get(bar) should be(Some(Seq(barB))) } it should "not rename already renamed targets if the module of the target is renamed" in { val renames = MutableRenameMap() renames.record(modA, modB) renames.record(foo, bar) renames.get(foo) should be(Some(Seq(bar))) } it should "rename modules if their circuit is renamed" in { val renames = MutableRenameMap() renames.record(cir, cir2) renames.get(modA) should be(Some(Seq(modA2))) } it should "rename targets if their circuit is renamed" in { val renames = MutableRenameMap() renames.record(cir, cir2) renames.get(foo) should be(Some(Seq(foo2))) } val TopCircuit = cir val Top = cir.module("Top") val Top_m = Top.instOf("m", "Middle") val Top_m_l = Top_m.instOf("l", "Leaf") val Top_m_l_a = Top_m_l.ref("a") val Top_m_la = Top_m.ref("l").field("a") val Middle = cir.module("Middle") val Middle2 = cir.module("Middle2") val Middle_la = Middle.ref("l").field("a") val Middle_l_a = Middle.instOf("l", "Leaf").ref("a") it should "rename targets if modules in the path are renamed" in { val renames = MutableRenameMap() renames.record(Middle, Middle2) renames.get(Top_m) should be(Some(Seq(Top.instOf("m", "Middle2")))) } it should "rename only the instance if instance and module in the path are renamed" in { val renames = MutableRenameMap() renames.record(Middle, Middle2) renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) } it should "rename targets if instance in the path are renamed" in { val renames = MutableRenameMap() renames.record(Top.instOf("m", "Middle"), Top.instOf("m2", "Middle")) renames.get(Top_m) should be(Some(Seq(Top.instOf("m2", "Middle")))) } it should "rename targets if instance and ofmodule in the path are renamed" in { val renames = MutableRenameMap() val Top_m2 = Top.instOf("m2", "Middle2") renames.record(Top_m, Top_m2) renames.get(Top_m) should be(Some(Seq(Top_m2))) } it should "properly do nothing if no remaps" in { val renames = MutableRenameMap() renames.get(Top_m_l_a) should be(None) } it should "properly rename if leaf is inlined" in { val renames = MutableRenameMap() renames.record(Middle_l_a, Middle_la) renames.get(Top_m_l_a) should be(Some(Seq(Top_m_la))) } it should "properly rename if middle is inlined" in { val renames = MutableRenameMap() renames.record(Top_m_l, Top.instOf("m_l", "Leaf")) renames.get(Top_m_l_a) should be(Some(Seq(Top.instOf("m_l", "Leaf").ref("a")))) } it should "properly rename if leaf and middle are inlined" in { val renames = MutableRenameMap() val inlined = Top.ref("m_l_a") renames.record(Top_m_l_a, inlined) renames.record(Top_m_l, Nil) renames.record(Top_m, Nil) renames.get(Top_m_l_a) should be(Some(Seq(inlined))) } it should "quickly rename a target with a long path" in { (0 until 50 by 10).foreach { endIdx => val renames = MutableRenameMap() renames.record(TopCircuit.module("Y0"), TopCircuit.module("X0")) val deepTarget = (0 until endIdx) .foldLeft(Top: IsModule) { (t, idx) => t.instOf("a", "A" + idx) } .ref("ref") val (millis, rename) = firrtl.Utils.time(renames.get(deepTarget)) //rename should be(None) } } it should "rename only once with multiple renames" in { val renames = MutableRenameMap() val Middle2 = cir.module("Middle2") renames.record(Middle, Middle2) renames.record(Middle.ref("l"), Middle.ref("lx")) renames.get(Middle.ref("l")) should be(Some(Seq(Middle.ref("lx")))) } it should "rename with fields" in { val Middle_o = Middle.ref("o") val Middle_i = Middle.ref("i") val Middle_o_f = Middle.ref("o").field("f") val Middle_i_f = Middle.ref("i").field("f") val renames = MutableRenameMap() renames.record(Middle_o, Middle_i) renames.get(Middle_o_f) should be(Some(Seq(Middle_i_f))) } it should "rename instances with same ofModule" in { val Middle_o = Middle.instOf("o", "O") val Middle_i = Middle.instOf("i", "O") val renames = MutableRenameMap() renames.record(Middle_o, Middle_i) renames.get(Middle.instOf("o", "O")) should be(Some(Seq(Middle.instOf("i", "O")))) } it should "not treat references as instances targets" in { val Middle_o = Middle.ref("o") val Middle_i = Middle.ref("i") val renames = MutableRenameMap() renames.record(Middle_o, Middle_i) renames.get(Middle.instOf("o", "O")) should be(None) } it should "be able to rename weird stuff" in { // Renaming `from` to each of the `tos` at the same time should be ok case class BadRename(from: CompleteTarget, tos: Seq[CompleteTarget]) val badRenames = Seq( //BadRename(foo, Seq(cir)), //BadRename(foo, Seq(modB)), //BadRename(modA, Seq(fooB)), //BadRename(modA, Seq(cir)), //BadRename(cir, Seq(foo)), //BadRename(cir, Seq(modA)), BadRename(cir, Seq(cir2, cir3)) ) // Run all BadRename tests for (BadRename(from, tos) <- badRenames) { val fromN = from val tosN = tos.mkString(", ") //it should s"error if a $fromN is renamed to $tosN" in { val renames = MutableRenameMap() for (to <- tos) { (from, to) match { case (f: CircuitTarget, t: CircuitTarget) => renames.record(f, t) case (f: IsMember, t: IsMember) => renames.record(f, t) case _ => sys.error("Unexpected!") } } //a [FIRRTLException] shouldBe thrownBy { renames.get(from) //} //} } } it should "not error if a circular rename occurs" in { val renames = MutableRenameMap() val top = CircuitTarget("Top") renames.record(top.module("A"), top.module("B").instOf("c", "C")) renames.record(top.module("B"), top.module("A").instOf("c", "C")) renames.get(top.module("A")) should be { Some(Seq(top.module("B").instOf("c", "C"))) } } it should "not error if a swapping rename occurs" in { val renames = MutableRenameMap() val top = CircuitTarget("Top") renames.record(top.module("A"), top.module("B")) renames.record(top.module("B"), top.module("A")) renames.get(top.module("A")) should be(Some(Seq(top.module("B")))) renames.get(top.module("B")) should be(Some(Seq(top.module("A")))) } it should "error if a reference is renamed to a module and vice versa" in { val renames = MutableRenameMap() val top = CircuitTarget("Top") renames.record(top.module("A").ref("ref"), top.module("B")) renames.record(top.module("C"), top.module("D").ref("ref")) a[IllegalRenameException] shouldBe thrownBy { renames.get(top.module("C")) } a[IllegalRenameException] shouldBe thrownBy { renames.get(top.module("A").ref("ref").field("field")) } renames.get(top.module("A").instOf("ref", "R")) should be(None) } it should "error if we rename an instance's ofModule into a non-module" in { val renames = MutableRenameMap() val top = CircuitTarget("Top") renames.record(top.module("C"), top.module("D").ref("x")) a[IllegalRenameException] shouldBe thrownBy { renames.get(top.module("A").instOf("c", "C")) } } it should "error if path is renamed into a non-path" ignore { val renames = MutableRenameMap() val top = CircuitTarget("Top") renames.record(top.module("E").instOf("f", "F"), top.module("E").ref("g")) a[IllegalRenameException] shouldBe thrownBy { renames.get(top.module("E").instOf("f", "F").ref("g")) } } it should "rename reference targets with paths if their corresponding pathless target are renamed" in { val cir = CircuitTarget("Top") val modTop = cir.module("Top") val modA = cir.module("A") val aggregate = modA.ref("agg") val subField1 = aggregate.field("field1") val subField2 = aggregate.field("field2") val lowered1 = aggregate.copy(ref = "agg_field1") val lowered2 = aggregate.copy(ref = "agg_field2") // simulating LowerTypes transform val renames = MutableRenameMap() renames.record(subField1, lowered1) renames.record(subField2, lowered2) renames.record(aggregate, Seq(lowered1, lowered2)) val path = modTop.instOf("b", "B").instOf("a", "A") val testRef1 = subField1.setPathTarget(path) renames.get(testRef1) should be { Some(Seq(testRef1.copy(ref = "agg_field1", component = Nil))) } } // ~Top|Module/i1:I1>foo.field, where rename map contains ~Top|Module/i1:I1>foo -> ~Top|Module/i1:I1>bar. it should "properly rename reference targets with the same paths" in { val cir = CircuitTarget("Top") val modTop = cir.module("Top") val mod = cir.module("Module") val path = mod.instOf("i1", "I1") val oldAgg = mod.ref("foo").setPathTarget(path) val newAgg = mod.ref("bar").setPathTarget(path) val renames = MutableRenameMap() renames.record(oldAgg, newAgg) val testRef = oldAgg.field("field") renames.get(testRef) should be { Some(Seq(newAgg.field("field"))) } } it should "properly rename reference targets with partially matching paths" in { val cir = CircuitTarget("Top") val modTop = cir.module("Top") val modA = cir.module("A") val modB = cir.module("B") val path = modB.instOf("a", "A") val oldRef = modA.ref("oldRef").setPathTarget(path) val newRef = modA.ref("newRef").setPathTarget(path) val renames = MutableRenameMap() renames.record(oldRef, newRef) val testRef = oldRef.addHierarchy("B", "b") renames.get(testRef) should be { Some(Seq(newRef.addHierarchy("B", "b"))) } } it should "properly rename reference targets with partially matching paths and partially matching target tokens" in { val cir = CircuitTarget("Top") val modTop = cir.module("Top") val modA = cir.module("A") val modB = cir.module("B") val path = modB.instOf("a", "A") val oldAgg = modA.ref("oldAgg").setPathTarget(path).field("field1") val newAgg = modA.ref("newAgg").setPathTarget(path) val renames = MutableRenameMap() renames.record(oldAgg, newAgg) val testRef = oldAgg.addHierarchy("B", "b").field("field2") renames.get(testRef) should be { Some(Seq(newAgg.addHierarchy("B", "b").field("field2"))) } } it should "rename targets with multiple renames starting from most specific to least specific" in { val cir = CircuitTarget("Top") val modTop = cir.module("Top") val modA = cir.module("A") val modB = cir.module("B") val modC = cir.module("C") // from: ~Top|A/b:B/c:C>ref.f1.f2.f3 // to: ~Top|A/b:B/c:C>ref.f1.f2.f333 // renamed first because it is an exact match val from1 = modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f2") .field("f3") val to1 = modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f2") .field("f33") // from: ~Top|A/b:B/c:C>ref.f1.f2 // to: ~Top|A/b:B/c:C>ref.f1 // renamed second because it is a parent target val from2 = modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f2") val to2 = modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f22") // from: ~Top|B/c:C>ref.f1 // to: ~Top|B/c:C>ref.f11 // renamed third because it has a smaller hierarchy val from3 = modB .instOf("c", "C") .ref("ref") .field("f1") val to3 = modB .instOf("c", "C") .ref("ref") .field("f11") // from: ~Top|C>ref // to: ~Top|C>refref // renamed last because it has no path val from4 = modC.ref("ref") val to4 = modC.ref("refref") val renames1 = MutableRenameMap() renames1.record(from1, to1) renames1.record(from2, to2) renames1.record(from3, to3) renames1.record(from4, to4) renames1.get(from1) should be { Some( Seq( modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f2") .field("f33") ) ) } val renames2 = MutableRenameMap() renames2.record(from2, to2) renames2.record(from3, to3) renames2.record(from4, to4) renames2.get(from1) should be { Some( Seq( modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f1") .field("f22") .field("f3") ) ) } val renames3 = MutableRenameMap() renames3.record(from3, to3) renames3.record(from4, to4) renames3.get(from1) should be { Some( Seq( modA .instOf("b", "B") .instOf("c", "C") .ref("ref") .field("f11") .field("f2") .field("f3") ) ) } } it should "correctly handle renaming of modules to instances" in { val cir = CircuitTarget("Top") val renames = MutableRenameMap() val from = cir.module("C") val to = cir.module("D").instOf("e", "E").instOf("f", "F") renames.record(from, to) renames.get(cir.module("C")) should be { Some(Seq(cir.module("D").instOf("e", "E").instOf("f", "F"))) } renames.get(cir.module("A").instOf("b", "B").instOf("c", "C")) should be { Some(Seq(cir.module("A").instOf("b", "B").instOf("c", "D").instOf("e", "E").instOf("f", "F"))) } } it should "correctly handle renaming of paths and components at the same time" in { val cir = CircuitTarget("Top") val renames = MutableRenameMap() val from = cir.module("C").ref("foo").field("bar") val to = cir.module("D").instOf("e", "E").instOf("f", "F").ref("foo").field("foo") renames.record(from, to) renames.get(cir.module("A").instOf("b", "B").instOf("c", "C").ref("foo").field("bar")) should be { Some( Seq( cir .module("A") .instOf("b", "B") .instOf("c", "D") .instOf("e", "E") .instOf("f", "F") .ref("foo") .field("foo") ) ) } } it should "error if an instance is renamed to a ReferenceTarget" in { val top = CircuitTarget("Top").module("Top") val renames = MutableRenameMap() val from = top.instOf("a", "A") val to = top.ref("b") renames.record(from, to) a[IllegalRenameException] shouldBe thrownBy { renames.get(from) } } it should "not allow renaming of instances even if there is a matching reference rename" in { val top = CircuitTarget("Top").module("Top") val renames = MutableRenameMap() val from = top.ref("a") val to = top.ref("b") renames.record(from, to) renames.get(top.instOf("a", "Foo")) should be(None) } it should "correctly chain renames together" in { val top = CircuitTarget("Top") val renames1 = MutableRenameMap() val from1 = top.module("A") val to1 = top.module("Top").instOf("b", "B") renames1.record(from1, to1) val renames2 = MutableRenameMap() val from2 = top.module("B") val to2 = top.module("B1") renames2.record(from2, to2) val renames = renames1.andThen(renames2) renames.get(from1) should be { Some(Seq(top.module("Top").instOf("b", "B1"))) } renames.get(from2) should be { Some(Seq(to2)) } } it should "correctly chain deleted targets" in { val top = CircuitTarget("Top") val modA = top.module("A") val modA1 = top.module("A1") val modB = top.module("B") val modB1 = top.module("B1") val renames1 = MutableRenameMap() renames1.delete(modA) renames1.record(modB, modB1) val renames2 = MutableRenameMap() renames2.record(modA, modA1) renames2.delete(modB1) val renames = renames1.andThen(renames2) renames.get(modA) should be { Some(Seq.empty) } renames.get(modB) should be { Some(Seq.empty) } } it should "correctly ++ renameMaps" in { val top = CircuitTarget("Top") val modA = top.module("A") val modA1 = top.module("A1") val modA2 = top.module("A1") val modB = top.module("B") val modB1 = top.module("B1") val modC = top.module("C") val modC1 = top.module("C1") val renames1 = MutableRenameMap() renames1.record(modA, modA1) renames1.record(modC, modC1) val renames2 = MutableRenameMap() renames2.record(modA, modA2) renames2.record(modB, modB1) val renames = renames1 ++ renames2 renames.get(modA) should be { Some(Seq(modA2)) } renames.get(modB) should be { Some(Seq(modB1)) } renames.get(modC) should be { Some(Seq(modC1)) } } it should "be able to inline instances" in { val top = CircuitTarget("Top") val inlineRename1 = { val inlineMod = top.module("A") val inlineInst = top.module("A").instOf("b", "B") val oldRef = inlineMod.ref("bar") val prefixRef = inlineMod.ref("foo") val renames1 = MutableRenameMap() renames1.record(inlineInst, inlineMod) val renames2 = MutableRenameMap() renames2.record(oldRef, prefixRef) renames1.andThen(renames2) } val inlineRename2 = { val inlineMod = top.module("A1") val inlineInst = top.module("A1").instOf("b", "B1") val oldRef = inlineMod.ref("bar") val prefixRef = inlineMod.ref("foo") val renames1 = MutableRenameMap() renames1.record(inlineInst, inlineMod) val renames2 = MutableRenameMap() renames2.record(oldRef, prefixRef) renames1.andThen(renames2) } val renames = inlineRename1 ++ inlineRename2 renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { Some(Seq(top.module("A").ref("foo"))) } renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { Some(Seq(top.module("A1").ref("foo"))) } } it should "be able to dedup modules" in { val top = CircuitTarget("Top") val topMod = top.module("Top") val dedupedMod = top.module("A") val dupMod1 = top.module("A1") val dupMod2 = top.module("A2") val relPath1 = dupMod1.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A1") val relPath2 = dupMod2.addHierarchy("Foo", "a") //top.module("Foo").instOf("a", "A2") val absPath1 = relPath1.addHierarchy("Top", "foo") val absPath2 = relPath2.addHierarchy("Top", "foo") val renames1 = MutableRenameMap() renames1.record(dupMod1, absPath1) renames1.record(dupMod2, absPath2) renames1.record(relPath1, absPath1) renames1.record(relPath2, absPath2) val renames2 = MutableRenameMap() renames2.record(dupMod1, dedupedMod) renames2.record(dupMod2, dedupedMod) val renames = renames1.andThen(renames2) renames.get(dupMod1.instOf("foo", "Bar").ref("ref")) should be { Some(Seq(absPath1.copy(ofModule = "A").instOf("foo", "Bar").ref("ref"))) } renames.get(dupMod2.ref("ref")) should be { Some(Seq(absPath2.copy(ofModule = "A").ref("ref"))) } renames.get(absPath1.instOf("b", "B").ref("ref")) should be { Some(Seq(absPath1.copy(ofModule = "A").instOf("b", "B").ref("ref"))) } } it should "should able to chain many rename maps" in { val top = CircuitTarget("Top") val inlineRename1 = { val inlineMod = top.module("A") val inlineInst = top.module("A").instOf("b", "B") val oldRef = inlineMod.ref("bar") val prefixRef = inlineMod.ref("foo") val renames1 = MutableRenameMap() renames1.record(inlineInst, inlineMod) val renames2 = MutableRenameMap() renames2.record(oldRef, prefixRef) renames1.andThen(renames2) } val inlineRename2 = { val inlineMod = top.module("A1") val inlineInst = top.module("A1").instOf("b", "B1") val oldRef = inlineMod.ref("bar") val prefixRef = inlineMod.ref("foo") val renames1 = MutableRenameMap() renames1.record(inlineInst, inlineMod) val renames2 = MutableRenameMap() renames2.record(oldRef, prefixRef) inlineRename1.andThen(renames1).andThen(renames2) } val renames = inlineRename2 renames.get(top.module("A").instOf("b", "B").ref("bar")) should be { Some(Seq(top.module("A").ref("foo"))) } renames.get(top.module("A1").instOf("b", "B1").ref("bar")) should be { Some(Seq(top.module("A1").ref("foo"))) } } it should "should able to chain chained rename maps" in { val top = CircuitTarget("Top").module("Top") val foo1 = top.instOf("foo1", "Mod") val foo2 = top.instOf("foo2", "Mod") val foo3 = top.instOf("foo3", "Mod") val bar1 = top.instOf("bar1", "Mod") val bar2 = top.instOf("bar2", "Mod") val foo1Rename = MutableRenameMap() val foo2Rename = MutableRenameMap() val bar1Rename = MutableRenameMap() val bar2Rename = MutableRenameMap() foo1Rename.record(foo1, foo2) foo2Rename.record(foo2, foo3) bar1Rename.record(foo3, bar1) bar2Rename.record(bar1, bar2) val chained1 = foo1Rename.andThen(foo2Rename) val chained2 = bar1Rename.andThen(bar2Rename) val renames = chained1.andThen(chained2) renames.get(foo1) should be { Some(Seq(bar2)) } } it should "record a self-rename" in { val top = CircuitTarget("Top").module("Top") val foo = top.instOf("foo", "Mod") val bar = top.instOf("bar", "Mod") val r = MutableRenameMap() r.record(foo, bar) r.record(foo, foo) r.get(foo) should not be (empty) (r.get(foo).get should contain).allOf(foo, bar) } it should "not record the same rename multiple times" in { val top = CircuitTarget("Top").module("Top") val foo = top.instOf("foo", "Mod") val bar = top.instOf("bar", "Mod") val r = MutableRenameMap() r.record(foo, bar) r.record(foo, bar) r.get(foo) should not be (empty) r.get(foo).get should contain theSameElementsAs Seq(bar) } it should "not circularly rename" in { val top = CircuitTarget("Top").module("Top") val foo = top.instOf("foo", "Mod") val Mod = CircuitTarget("Top").module("Mod") val Mod2 = CircuitTarget("Top").module("Mod2") val r = MutableRenameMap() r.record(foo, Mod) r.record(Mod, Mod2) r.get(foo) should not be (empty) r.get(foo).get should contain theSameElementsAs Seq(Mod) r.get(Mod).get should contain theSameElementsAs Seq(Mod2) } it should "delete instances of deleted modules" in { val top = CircuitTarget("Top").module("Top") val foo = top.instOf("foo", "Mod") val Mod = CircuitTarget("Top").module("Mod") val r = MutableRenameMap() r.delete(Mod) r.get(foo) should be(Some(Nil)) } it should "rename an instance if it has been renamed" in { // this could happen if the instance name needed to be uniquified to avoid clashes in LowerTypes val top = CircuitTarget("top").module("top") val r = MutableRenameMap() val i = top.instOf("i", "child") val i_ = top.instOf("i_", "child") r.record(i, i_) r.get(i) should be(Some(Seq(i_))) r.get(i.ref("a")) should be(Some(Seq(i_.ref("a")))) } it should "rename references to an instance's ports if the ports of the module have been renamed" in { // this could happen if the port name needed to be uniquified to avoid clashes in LowerTypes val top = CircuitTarget("top").module("top") val child = CircuitTarget("top").module("child") val r = MutableRenameMap() r.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) val i = top.instOf("i", "child") r.get(i.ref("a")) should be(Some(Seq(i.ref("a_0"), i.ref("a_1")))) } it should "rename references to renamed instance's ports if the ports of the module have been renamed" in { // this could happen if the instance as well as the port name needed to be uniquified to avoid clashes in LowerTypes val top = CircuitTarget("top").module("top") val child = CircuitTarget("top").module("child") val portRenames = MutableRenameMap() portRenames.record(child.ref("a"), Seq(child.ref("a_0"), child.ref("a_1"))) val instanceRenames = MutableRenameMap() val i = top.instOf("i", "child") val i_ = top.instOf("i_", "child") instanceRenames.record(i, i_) // The port and instance renames must be *explicitly* chained! val r = portRenames.andThen(instanceRenames) r.get(i.ref("a")) should be(Some(Seq(i_.ref("a_0"), i_.ref("a_1")))) } }