Skip to content

Commit

Permalink
Make requireTypeEquivalent public and add context message (#4243) (#4247
Browse files Browse the repository at this point in the history
)

* make requireTypeEquivalent public via DataMirror and add a message
* add test cases

(cherry picked from commit c324ac5)

Co-authored-by: Megan Wachs <[email protected]>
  • Loading branch information
mergify[bot] and mwachs5 authored Jul 8, 2024
1 parent 9f3b98b commit e52eccc
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
7 changes: 5 additions & 2 deletions core/src/main/scala/chisel3/Data.scala
Original file line number Diff line number Diff line change
Expand Up @@ -606,15 +606,18 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {

/** Require that two things are type equivalent, and if they are not, print a helpful error message as
* to why not.
*
* @param that the Data to compare to for type equivalence
* @param message if they are not type equivalent, contextual message to add to the exception thrown
*/
private[chisel3] def requireTypeEquivalent(that: Data): Unit = {
private[chisel3] def requireTypeEquivalent(that: Data, message: String = ""): Unit = {
require(
this.typeEquivalent(that), {
val reason = this
.findFirstTypeMismatch(that, strictTypes = true, strictWidths = true, strictProbeInfo = true)
.map(s => s"\nbecause $s")
.getOrElse("")
s"$this is not typeEquivalent to $that$reason"
s"$message$this is not typeEquivalent to $that$reason"
}
)
}
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/scala/chisel3/reflect/DataMirror.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ object DataMirror {
*/
def checkTypeEquivalence(x: Data, y: Data): Boolean = x.typeEquivalent(y)

/** Require that two things are type equivalent
*
* If they are not, print a helpful error message as
* to why not.
*
* Requires structural, alignment, width, probe, color type equivalent
* @param x First Chisel type
* @param y Second chisel type
* @param message if they are not type equivalent, contextual message to add to the exception thrown
*/
def requireTypeEquivalent(x: Data, y: Data, message: String = ""): Unit = {
x.requireTypeEquivalent(y, message)
}

/** Check if two Chisel types have the same alignments for all matching members
*
* This means that for matching members in Aggregates, they must have matching member alignments relative to the parent type
Expand Down
26 changes: 26 additions & 0 deletions src/test/scala/chisel3/TypeEquivalenceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ object TypeEquivalenceSpec {
val c = if (hasC) Some(UInt(8.W)) else None
}

class FooParent(hasC: Boolean) extends Bundle {
val foo = new Foo(hasC)
}

class FooGrandparent(hasC: Boolean) extends Bundle {
val bar = new FooParent(hasC)
}

class Bar(bWidth: Int = 8) extends Bundle {
val a = UInt(8.W)
val b = UInt(bWidth.W)
Expand Down Expand Up @@ -340,4 +348,22 @@ class TypeEquivalenceSpec extends AnyFlatSpec {
)
}

behavior.of("Data.requireTypeEquivalent")

it should "have a good user message if it fails for wrong scala type" in {
val result = the[IllegalArgumentException] thrownBy {
Bool().requireTypeEquivalent(UInt(1.W), "This test should fail, because: ")
}
result.getMessage should include("This test should fail, because: Bool is not typeEquivalent to UInt<1>")
}

it should "have a good user message if it fails for mismatched bundles" in {
val result = the[IllegalArgumentException] thrownBy {
(new FooGrandparent(true)).requireTypeEquivalent(new FooGrandparent(false), "This test should fail, because: ")
}
result.getMessage should include("This test should fail, because:")
// Also says 'FooGrandparent$1 is not typeEquivalent to FooGrandparent$1' which isn't terribly interesting to match on
result.getMessage should include(".bar.foo.c: Dangling field on Left")
}

}

0 comments on commit e52eccc

Please sign in to comment.