Skip to content

Commit 79793df

Browse files
author
Oron Port
committed
refactor: Improve type reference handling in replacement context patching
This commit enhances the reference replacement mechanism by: - Adding tracking for type reference repetitions - Preventing premature removal of type references used in multiple contexts - Updating the replacement context to handle type references more robustly
1 parent 4f39123 commit 79793df

File tree

2 files changed

+50
-20
lines changed

2 files changed

+50
-20
lines changed

compiler/stages/src/main/scala/dfhdl/compiler/stages/ExplicitCondExprAssign.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ case object ExplicitCondExprAssign extends Stage:
1212
def dependencies: List[Stage] = List()
1313
def nullifies: Set[Stage] = Set(DropUnreferencedAnons)
1414

15-
object IgnoreTypeRefs extends Patch.Replace.RefFilter:
16-
def apply(refs: Set[DFRefAny])(using MemberGetSet): Set[DFRefAny] =
17-
refs.filterNot(_.isTypeRef)
18-
1915
def transform(designDB: DB)(using MemberGetSet, CompilerOptions): DB =
2016
var headers = List.empty[DFConditional.Header]
2117
extension (ch: DFConditional.Header)
@@ -68,8 +64,7 @@ case object ExplicitCondExprAssign extends Stage:
6864
val patchList2 = headers.map { h =>
6965
h -> Patch.Replace(
7066
h.updateDFType(DFUnit),
71-
Patch.Replace.Config.FullReplacement,
72-
IgnoreTypeRefs
67+
Patch.Replace.Config.FullReplacement
7368
)
7469
}
7570
designDB

core/src/main/scala/dfhdl/compiler/patching/ReplacementContext.scala

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import dfhdl.internals.invert
44
private final case class ReplacementContext(
55
refTable: Map[DFRefAny, DFMember],
66
memberTable: Map[DFMember, Set[DFRefAny]],
7-
memberRepTable: Map[DFMember, List[(DFMember, Patch.Replace.RefFilter)]]
7+
memberRepTable: Map[DFMember, List[(DFMember, Patch.Replace.RefFilter)]],
8+
typeRefRepeats: Map[DFRef.TypeRef, Int]
89
)(using getSet: MemberGetSet):
910
def changeRef(origRef: DFRefAny, updateMember: DFMember): ReplacementContext =
1011
// println("changeRef", origRef, updateMember)
@@ -55,10 +56,12 @@ private final case class ReplacementContext(
5556
val purgedRefs = config match
5657
case Patch.Replace.Config.ChangeRefOnly => Set()
5758
case _ => refFilter(origMember.getRefs.toSet -- keepRefs)
59+
val (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs) =
60+
getUpdatedTypeRefCount(purgedRefs)
5861
val updatedRefTable: Map[DFRefAny, DFMember] =
5962
replacementHistory.foldRight(refTable) { case ((rm, rf), rt) =>
6063
rf(refs).foldLeft(rt)((rt2, r) => rt2.updated(r, rm))
61-
} -- purgedRefs
64+
} -- purgedRefsWithoutRepeatedTypeRefs
6265
val updatedMemberRepTable: Map[DFMember, List[(DFMember, Patch.Replace.RefFilter)]] =
6366
refFilter match
6467
// An all inclusive filter is purging all other replacement histories, so we only save it alone
@@ -70,24 +73,56 @@ private final case class ReplacementContext(
7073
val updatedMemberTable = purgedRefs.foldLeft(memberTable) { case (mt, r) =>
7174
mt.updatedWith(r.get)(SomeRefs => Some(SomeRefs.get - r))
7275
} + (latestRepMember -> refs)
73-
ReplacementContext(updatedRefTable, updatedMemberTable, updatedMemberRepTable)
76+
ReplacementContext(
77+
updatedRefTable,
78+
updatedMemberTable,
79+
updatedMemberRepTable,
80+
updatedTypeRefRepeats
81+
)
7482
end if
7583
end replaceMember
7684

77-
def removeMember(origMember: DFMember): ReplacementContext =
78-
// total references to be removed are both
79-
// * refs - directly referencing the member
80-
// * originRefs - the member is referencing other members with a two-way
81-
// reference that points back to it.
82-
val totalRefs =
83-
memberTable.getOrElse(origMember, Set()) ++ origMember.getRefs.filter {
84-
case _: DFRef.TypeRef => false
85-
case _ => true
85+
// returns the updated type ref count and the purged refs without repeated type refs
86+
private def getUpdatedTypeRefCount(
87+
purgedRefs: Set[DFRefAny]
88+
): (Map[DFRef.TypeRef, Int], Set[DFRefAny]) =
89+
val updatedTypeRefRepeats = purgedRefs.view
90+
.collect { case ref: DFRef.TypeRef => ref }
91+
.foldLeft(typeRefRepeats) { case (counts, ref) =>
92+
counts.get(ref) match
93+
case Some(count) => counts.updated(ref, count - 1)
94+
case None => counts
8695
}
87-
this.copy(refTable = this.refTable -- totalRefs)
96+
val purgedRefsWithoutRepeatedTypeRefs = purgedRefs.filter {
97+
case ref: DFRef.TypeRef => updatedTypeRefRepeats.get(ref).exists(_ == 0)
98+
case _ => true
99+
}
100+
(updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs)
101+
end getUpdatedTypeRefCount
102+
103+
def removeMember(origMember: DFMember): ReplacementContext =
104+
// Total references to be removed are:
105+
// * refs from memberTable - references from other members to this member
106+
// * refs from origMember - references from this member to other members
107+
// Together these cover both directions of two-way references
108+
val purgedRefs =
109+
memberTable.getOrElse(origMember, Set()) ++ origMember.getRefs
110+
val (updatedTypeRefRepeats, purgedRefsWithoutRepeatedTypeRefs) =
111+
getUpdatedTypeRefCount(purgedRefs)
112+
this.copy(
113+
refTable = this.refTable -- purgedRefsWithoutRepeatedTypeRefs,
114+
typeRefRepeats = updatedTypeRefRepeats
115+
)
88116

89117
end ReplacementContext
90118

91119
private object ReplacementContext:
92120
def fromRefTable(refTable: Map[DFRefAny, DFMember])(using MemberGetSet): ReplacementContext =
93-
ReplacementContext(refTable, refTable.invert, Map())
121+
val typeRefRepeats =
122+
getSet.designDB.members.view
123+
.flatMap(_.getRefs.view.collect { case ref: DFRef.TypeRef => ref })
124+
.groupBy(identity)
125+
.view
126+
.mapValues(_.size)
127+
.toMap
128+
ReplacementContext(refTable, refTable.invert, Map(), typeRefRepeats)

0 commit comments

Comments
 (0)