clash-prelude 1.10.0 → 1.10.1
raw patch · 35 files changed
+1581/−33 lines, 35 filesdep +checked-literalsdep +processdep +temporarydep −data-binary-ieee754dep ~string-interpolatedep ~timePVP ok
version bump matches the API change (PVP)
Dependencies added: checked-literals, process, temporary
Dependencies removed: data-binary-ieee754
Dependency ranges changed: string-interpolate, time
API changes (from Hackage documentation)
+ Clash.Num.Erroring: instance (GHC.Classes.Ord a, Clash.Class.Num.SaturatingNum a) => Clash.Class.Num.SaturatingNum (Clash.Num.Erroring.Erroring a)
+ Clash.Num.Erroring: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Num.Erroring.Erroring a)
+ Clash.Num.Erroring: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Num.Erroring.Erroring a)
+ Clash.Num.Erroring: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Num.Erroring.Erroring a)
+ Clash.Num.Erroring: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Num.Erroring.Erroring a)
+ Clash.Num.Overflowing: instance (GHC.Classes.Ord a, Clash.Class.Num.SaturatingNum a) => Clash.Class.Num.SaturatingNum (Clash.Num.Overflowing.Overflowing a)
+ Clash.Num.Overflowing: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Num.Overflowing.Overflowing a)
+ Clash.Num.Overflowing: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Num.Overflowing.Overflowing a)
+ Clash.Num.Overflowing: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Num.Overflowing.Overflowing a)
+ Clash.Num.Overflowing: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Num.Overflowing.Overflowing a)
+ Clash.Num.Saturating: instance (GHC.Classes.Ord a, Clash.Class.Num.SaturatingNum a) => Clash.Class.Num.SaturatingNum (Clash.Num.Saturating.Saturating a)
+ Clash.Num.Saturating: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Num.Saturating.Saturating a)
+ Clash.Num.Saturating: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Num.Saturating.Saturating a)
+ Clash.Num.Saturating: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Num.Saturating.Saturating a)
+ Clash.Num.Saturating: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Num.Saturating.Saturating a)
+ Clash.Num.Wrapping: instance (GHC.Enum.Bounded a, Clash.Class.Num.SaturatingNum a) => Clash.Class.Num.SaturatingNum (Clash.Num.Wrapping.Wrapping a)
+ Clash.Num.Wrapping: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Num.Wrapping.Wrapping a)
+ Clash.Num.Wrapping: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Num.Wrapping.Wrapping a)
+ Clash.Num.Wrapping: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Num.Wrapping.Wrapping a)
+ Clash.Num.Wrapping: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Num.Wrapping.Wrapping a)
+ Clash.Num.Zeroing: instance (GHC.Classes.Ord a, Clash.Class.Num.SaturatingNum a) => Clash.Class.Num.SaturatingNum (Clash.Num.Zeroing.Zeroing a)
+ Clash.Num.Zeroing: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Num.Zeroing.Zeroing a)
+ Clash.Num.Zeroing: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Num.Zeroing.Zeroing a)
+ Clash.Num.Zeroing: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Num.Zeroing.Zeroing a)
+ Clash.Num.Zeroing: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Num.Zeroing.Zeroing a)
+ Clash.Signal.Delayed.Internal: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Signal.Delayed.Internal.DSignal dom delay a)
+ Clash.Signal.Delayed.Internal: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Signal.Delayed.Internal.DSignal dom delay a)
+ Clash.Signal.Delayed.Internal: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Signal.Delayed.Internal.DSignal dom delay a)
+ Clash.Signal.Delayed.Internal: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Signal.Delayed.Internal.DSignal dom delay a)
+ Clash.Signal.Internal: instance CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Signal.Internal.Signal dom a)
+ Clash.Signal.Internal: instance CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit a => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Signal.Internal.Signal dom a)
+ Clash.Signal.Internal: instance CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Signal.Internal.Signal dom a)
+ Clash.Signal.Internal: instance CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den a => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Signal.Internal.Signal dom a)
+ Clash.Sized.BitVector: type BitPositiveLiteralError lit = OutOfBounds ('ShowType lit) (UnsignedBounds Bit 1)
+ Clash.Sized.BitVector: type BitVectorPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (BitVector n) ((2 ^ n) - 1)) (CLog 2 (lit + 1)) n
+ Clash.Sized.Fixed: instance (Clash.Sized.Fixed.CheckFixedFrac (CheckedLiterals.Class.Rational.TypeNats.IsPowerOfTwo den) ('GHC.TypeError.Text str) den frac (Clash.Sized.Fixed.SFixed int frac), GHC.TypeError.Assert (Clash.Sized.Fixed.FitsNegativeSFixedRational num den int) (Clash.Sized.Fixed.SFixedNegativeRationalLiteralError ('GHC.TypeError.Text str) num den int)) => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Sized.Fixed.SFixed int frac)
+ Clash.Sized.Fixed: instance (Clash.Sized.Fixed.CheckFixedFrac (CheckedLiterals.Class.Rational.TypeNats.IsPowerOfTwo den) ('GHC.TypeError.Text str) den frac (Clash.Sized.Fixed.SFixed int frac), GHC.TypeError.Assert (Clash.Sized.Fixed.FitsPositiveSFixedRational num den int) (Clash.Sized.Fixed.SFixedPositiveRationalLiteralError ('GHC.TypeError.Text str) num den int)) => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Sized.Fixed.SFixed int frac)
+ Clash.Sized.Fixed: instance (GHC.TypeError.Assert (Data.Type.Bool.If (GHC.TypeNats.Div num den Data.Type.Ord.<=? 0) (GHC.TypeNats.Div num den Data.Type.Ord.<=? 0) (GHC.TypeLits.Extra.CLog 2 (GHC.TypeNats.Div num den GHC.TypeNats.+ 1) Data.Type.Ord.<=? int)) (Clash.Sized.Fixed.UFixedPositiveLiteralError ('GHC.TypeError.Text str) (GHC.TypeNats.Div num den) int), Clash.Sized.Fixed.CheckFixedFrac (CheckedLiterals.Class.Rational.TypeNats.IsPowerOfTwo den) ('GHC.TypeError.Text str) den frac (Clash.Sized.Fixed.UFixed int frac)) => CheckedLiterals.Class.Rational.CheckedPositiveRationalLiteral str num den (Clash.Sized.Fixed.UFixed int frac)
+ Clash.Sized.Fixed: instance Clash.Sized.Fixed.UFixedNegativeLiteralError ('GHC.TypeError.Text "-" 'GHC.TypeError.:<>: 'GHC.TypeError.ShowType lit) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Fixed.UFixed int frac)
+ Clash.Sized.Fixed: instance Clash.Sized.Fixed.UFixedNegativeLiteralError ('GHC.TypeError.Text str) => CheckedLiterals.Class.Rational.CheckedNegativeRationalLiteral str num den (Clash.Sized.Fixed.UFixed int frac)
+ Clash.Sized.Fixed: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) ((GHC.TypeLits.Extra.CLog 2 (lit GHC.TypeNats.+ 1) GHC.TypeNats.+ 1) Data.Type.Ord.<=? int)) (Clash.Sized.Fixed.SFixedPositiveLiteralError ('GHC.TypeError.ShowType lit) lit int) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Fixed.SFixed int frac)
+ Clash.Sized.Fixed: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) ((GHC.TypeLits.Extra.CLog 2 lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? int)) (Clash.Sized.Fixed.SFixedNegativeLiteralError ('GHC.TypeError.Text "-" 'GHC.TypeError.:<>: 'GHC.TypeError.ShowType lit) lit int) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Fixed.SFixed int frac)
+ Clash.Sized.Fixed: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) (GHC.TypeLits.Extra.CLog 2 (lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? int)) (Clash.Sized.Fixed.UFixedPositiveLiteralError ('GHC.TypeError.ShowType lit) lit int) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Fixed.UFixed int frac)
+ Clash.Sized.Fixed: type FixedPointNotEnoughFracError strLit den frac typ = NotExactlyRepresentableWithConstraint strLit typ (FractionalBitsNote (CLog 2 den)) (CLog 2 den) frac
+ Clash.Sized.Fixed: type FixedPointNotPow2Error strLit den typ = NotExactlyRepresentable strLit typ ('Text "The reduced denominator " ':<>: 'ShowType den ':<>: 'Text " is not a power of 2.")
+ Clash.Sized.Fixed: type SFixedNegativeLiteralError strLit lit int = PotentiallyOutOfBounds strLit (SignedIntegerBitsNote (CLog 2 lit + 1)) (CLog 2 lit + 1) int
+ Clash.Sized.Fixed: type SFixedNegativeRationalLiteralError strLit num den int = PotentiallyOutOfBounds strLit (SignedIntegerBitsNote (SFixedNegativeRationalRequiredIntBits num den)) (SFixedNegativeRationalRequiredIntBits num den) int
+ Clash.Sized.Fixed: type SFixedNegativeRationalRequiredIntBits (num :: Nat) (den :: Nat) = CLog 2 num + 1 - CLog 2 den
+ Clash.Sized.Fixed: type SFixedPositiveLiteralError strLit lit int = PotentiallyOutOfBounds strLit (SignedIntegerBitsNote (CLog 2 (lit + 1) + 1)) (CLog 2 (lit + 1) + 1) int
+ Clash.Sized.Fixed: type SFixedPositiveRationalLiteralError strLit num den int = PotentiallyOutOfBounds strLit (SignedIntegerBitsNote (SFixedPositiveRationalRequiredIntBits num den)) (SFixedPositiveRationalRequiredIntBits num den) int
+ Clash.Sized.Fixed: type SFixedPositiveRationalRequiredIntBits (num :: Nat) (den :: Nat) = CLog 2 (num + 1) + 1 - CLog 2 den
+ Clash.Sized.Fixed: type UFixedNegativeLiteralError strLit = OutOfBoundsBecause strLit ('Text "UFixed cannot represent negative numbers.")
+ Clash.Sized.Fixed: type UFixedPositiveLiteralError strLit lit int = PotentiallyOutOfBounds strLit (IntegerBitsNote (CLog 2 (lit + 1))) (CLog 2 (lit + 1)) int
+ Clash.Sized.Fixed: type family CheckFixedFrac (isPow2 :: Bool) (strLit :: ErrorMessage) (den :: Nat) (frac :: Nat) (typ :: Type) :: Constraint
+ Clash.Sized.Index: type IndexPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (Index n) (n - 1)) (lit + 1) n
+ Clash.Sized.Internal.BitVector: instance CheckedLiterals.Class.Integer.NegativeUnsignedError lit (Clash.Sized.Internal.BitVector.BitVector n) ((2 GHC.TypeNats.^ n) GHC.TypeNats.- 1) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Internal.BitVector.BitVector n)
+ Clash.Sized.Internal.BitVector: instance CheckedLiterals.Class.Integer.NegativeUnsignedError lit Clash.Sized.Internal.BitVector.Bit 1 => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit Clash.Sized.Internal.BitVector.Bit
+ Clash.Sized.Internal.BitVector: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) (GHC.TypeLits.Extra.CLog 2 (lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? n)) (Clash.Sized.Internal.BitVector.BitVectorPositiveLiteralError lit n) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Internal.BitVector.BitVector n)
+ Clash.Sized.Internal.BitVector: instance GHC.TypeError.Assert (lit Data.Type.Ord.<=? 1) (Clash.Sized.Internal.BitVector.BitPositiveLiteralError lit) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit Clash.Sized.Internal.BitVector.Bit
+ Clash.Sized.Internal.BitVector: type BitPositiveLiteralError lit = OutOfBounds ('ShowType lit) (UnsignedBounds Bit 1)
+ Clash.Sized.Internal.BitVector: type BitVectorPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (BitVector n) ((2 ^ n) - 1)) (CLog 2 (lit + 1)) n
+ Clash.Sized.Internal.CheckedLiterals: type AddConstraintFix required actual = 'Text "Possible fix: add a constraint: " ':<>: 'ShowType required ':<>: 'Text " <= " ':<>: 'ShowType actual ':<>: 'Text "."
+ Clash.Sized.Internal.CheckedLiterals: type CheckedLiteralUncheckedFix = 'Text "Possible fix: use 'uncheckedLiteral' from 'CheckedLiterals' to bypass this check."
+ Clash.Sized.Internal.CheckedLiterals: type FractionalBitsNote bits = 'Text "The fractional part needs at least " ':<>: 'ShowType bits ':<>: 'Text " bit(s)."
+ Clash.Sized.Internal.CheckedLiterals: type IntegerBitsNote bits = 'Text "Note: integer part needs at least " ':<>: 'ShowType bits ':<>: 'Text " bit(s)."
+ Clash.Sized.Internal.CheckedLiterals: type NotExactlyRepresentable strLit (typ :: Type) reason = TypeError ('Text "Literal " ':<>: strLit ':<>: 'Text " cannot be represented exactly by " ':<>: 'ShowType typ ':<>: 'Text "." ':$$: reason ':$$: CheckedLiteralUncheckedFix)
+ Clash.Sized.Internal.CheckedLiterals: type NotExactlyRepresentableWithConstraint strLit (typ :: Type) reason required actual = TypeError ('Text "Literal " ':<>: strLit ':<>: 'Text " cannot be represented exactly by " ':<>: 'ShowType typ ':<>: 'Text "." ':$$: reason ':$$: AddConstraintFix required actual ':$$: CheckedLiteralUncheckedFix)
+ Clash.Sized.Internal.CheckedLiterals: type OutOfBounds strLit details = TypeError ('Text "Literal " ':<>: strLit ':<>: 'Text " is out of bounds." ':$$: details ':$$: CheckedLiteralUncheckedFix)
+ Clash.Sized.Internal.CheckedLiterals: type OutOfBoundsBecause strLit reason = TypeError ('Text "Literal " ':<>: strLit ':<>: 'Text " is out of bounds, because " ':<>: reason ':$$: CheckedLiteralUncheckedFix)
+ Clash.Sized.Internal.CheckedLiterals: type PotentiallyOutOfBounds strLit details required actual = TypeError ('Text "Literal " ':<>: strLit ':<>: 'Text " is (potentially) out of bounds." ':$$: details ':$$: AddConstraintFix required actual ':$$: CheckedLiteralUncheckedFix)
+ Clash.Sized.Internal.CheckedLiterals: type SignedBounds (typ :: Type) minVal maxVal = 'ShowType typ ':<>: 'Text " has bounds: [-" ':<>: 'ShowType minVal ':<>: 'Text " .. " ':<>: 'ShowType maxVal ':<>: 'Text "]."
+ Clash.Sized.Internal.CheckedLiterals: type SignedIntegerBitsNote bits = 'Text "Note: integer part needs at least " ':<>: 'ShowType bits ':<>: 'Text " bit(s), including sign bit."
+ Clash.Sized.Internal.CheckedLiterals: type UnsignedBounds (typ :: Type) maxVal = 'ShowType typ ':<>: 'Text " has bounds: [0 .. " ':<>: 'ShowType maxVal ':<>: 'Text "]."
+ Clash.Sized.Internal.Index: instance CheckedLiterals.Class.Integer.NegativeUnsignedError lit (Clash.Sized.Internal.Index.Index n) (n GHC.TypeNats.- 1) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Internal.Index.Index n)
+ Clash.Sized.Internal.Index: instance GHC.TypeError.Assert ((lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? n) (Clash.Sized.Internal.Index.IndexPositiveLiteralError lit n) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Internal.Index.Index n)
+ Clash.Sized.Internal.Index: type IndexPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (Index n) (n - 1)) (lit + 1) n
+ Clash.Sized.Internal.Signed: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) ((GHC.TypeLits.Extra.CLog 2 (lit GHC.TypeNats.+ 1) GHC.TypeNats.+ 1) Data.Type.Ord.<=? n)) (Clash.Sized.Internal.Signed.SignedPositiveLiteralError lit n) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Internal.Signed.Signed n)
+ Clash.Sized.Internal.Signed: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) ((GHC.TypeLits.Extra.CLog 2 lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? n)) (Clash.Sized.Internal.Signed.SignedNegativeLiteralError lit n) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Internal.Signed.Signed n)
+ Clash.Sized.Internal.Signed: type SignedNegativeLiteralError lit n = PotentiallyOutOfBounds ('Text "-" ':<>: 'ShowType lit) (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1)) (CLog 2 lit + 1) n
+ Clash.Sized.Internal.Signed: type SignedPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1)) (CLog 2 (lit + 1) + 1) n
+ Clash.Sized.Internal.Unsigned: instance CheckedLiterals.Class.Integer.NegativeUnsignedError lit (Clash.Sized.Internal.Unsigned.Unsigned n) ((2 GHC.TypeNats.^ n) GHC.TypeNats.- 1) => CheckedLiterals.Class.Integer.CheckedNegativeIntegerLiteral lit (Clash.Sized.Internal.Unsigned.Unsigned n)
+ Clash.Sized.Internal.Unsigned: instance GHC.TypeError.Assert (Data.Type.Bool.If (lit Data.Type.Ord.<=? 0) (lit Data.Type.Ord.<=? 0) (GHC.TypeLits.Extra.CLog 2 (lit GHC.TypeNats.+ 1) Data.Type.Ord.<=? n)) (Clash.Sized.Internal.Unsigned.UnsignedPositiveLiteralError lit n) => CheckedLiterals.Class.Integer.CheckedPositiveIntegerLiteral lit (Clash.Sized.Internal.Unsigned.Unsigned n)
+ Clash.Sized.Internal.Unsigned: type UnsignedPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (Unsigned n) ((2 ^ n) - 1)) (CLog 2 (lit + 1)) n
+ Clash.Sized.Signed: type SignedNegativeLiteralError lit n = PotentiallyOutOfBounds ('Text "-" ':<>: 'ShowType lit) (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1)) (CLog 2 lit + 1) n
+ Clash.Sized.Signed: type SignedPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1)) (CLog 2 (lit + 1) + 1) n
+ Clash.Sized.Unsigned: type UnsignedPositiveLiteralError lit n = PotentiallyOutOfBounds ('ShowType lit) (UnsignedBounds (Unsigned n) ((2 ^ n) - 1)) (CLog 2 (lit + 1)) n
Files
- CHANGELOG.md +67/−0
- clash-prelude.cabal +21/−6
- src/Clash/Annotations/TH.hs +1/−0
- src/Clash/Class/AutoReg/Internal.hs +1/−1
- src/Clash/Class/BitPack/Internal.hs +6/−6
- src/Clash/Num/Erroring.hs +43/−2
- src/Clash/Num/Overflowing.hs +96/−1
- src/Clash/Num/Saturating.hs +43/−2
- src/Clash/Num/Wrapping.hs +41/−0
- src/Clash/Num/Zeroing.hs +43/−2
- src/Clash/Signal/Delayed/Internal.hs +25/−0
- src/Clash/Signal/Internal.hs +25/−0
- src/Clash/Sized/BitVector.hs +3/−0
- src/Clash/Sized/Fixed.hs +184/−3
- src/Clash/Sized/Index.hs +4/−1
- src/Clash/Sized/Internal/BitVector.hs +58/−2
- src/Clash/Sized/Internal/CheckedLiterals.hs +101/−0
- src/Clash/Sized/Internal/Index.hs +44/−2
- src/Clash/Sized/Internal/Signed.hs +55/−2
- src/Clash/Sized/Internal/Unsigned.hs +44/−2
- src/Clash/Sized/Signed.hs +3/−0
- src/Clash/Sized/Unsigned.hs +4/−1
- tests/Clash/Tests/CheckedLiterals.hs +28/−0
- tests/Clash/Tests/CheckedLiterals/BitVector.hs +54/−0
- tests/Clash/Tests/CheckedLiterals/Common.hs +46/−0
- tests/Clash/Tests/CheckedLiterals/Fixed.hs +143/−0
- tests/Clash/Tests/CheckedLiterals/Index.hs +44/−0
- tests/Clash/Tests/CheckedLiterals/Signals.hs +42/−0
- tests/Clash/Tests/CheckedLiterals/Signed.hs +43/−0
- tests/Clash/Tests/CheckedLiterals/Unsigned.hs +43/−0
- tests/Clash/Tests/CheckedLiterals/Wrappers.hs +43/−0
- tests/Clash/Tests/Laws/SaturatingNum.hs +32/−0
- tests/Clash/Tests/TopEntityGeneration.hs +22/−0
- tests/Test/Tasty/AssertGhc.hs +127/−0
- tests/unittests.hs +2/−0
CHANGELOG.md view
@@ -1,5 +1,72 @@ # Changelog for the Clash project +## 1.10.1 *Aug 27th, 2026*++Highlights:+ * Very significant performance improvements, further detailed below. We also created a site https://clash-lang.github.io/clash-benchmarks/ where we track performance improvements. These graphs are for the current `master` branch, not for released Clash versions.+ * We have added support for the `checked-literals` package. Numeric literals (e.g., `5` or `3.2`) can now be checked at compile time. That is, you'll get a compile error if the literal does not fit the target type -- even in polymorphic contexts! You can enable the checker by adding the following to your project's Cabal file:++ ```+ library+ [..]++ build-depends:+ [..]+ checked-literals++ ghc-options: -fplugin=CheckedLiterals+ ```++ See https://clash-lang.org/blog/2026-04-07-checked-literals/.++Performance:+* `clash` and `clashi` now use GHC-style RTS defaults through executable `-with-rtsopts` flags instead of linking RTS hooks. The existing unused hooks have been removed. **Existing users should set `-with-rtsopts` to `-K512M -H -I5 -T` if they use their own Clash executable. These flags has been shown to give a ~25% compilation speed up in larger designs.** If you used a Clash starter project to initialize your design, you should change:++ ```haskell+ executable clash+ [..]+ ```++ To:++ ```haskell+ executable clash+ [..]+ ghc-options: "-with-rtsopts=-K512M -H -I5 -T"+ ```++ in the cabal file. See [#3252](https://github.com/clash-lang/clash-compiler/issues/3252).+* Improved normalization performance for repeated top-down rewrite loops by avoiding full root restarts after every successful rewrite. This gives a ~17% performance improvements on larger designs [#3249](https://github.com/clash-lang/clash-compiler/issues/3249).+* Clash now converts GHC Core to its own Clash Core in parallel. For larger projects, this can shave off ~40% of load times. See [#3299](https://github.com/clash-lang/clash-compiler/issues/3299).+* Clash now prunes the binders it collects from top modules when loading from precompiled core. For larger projects, this can shave off 15% of package loading times. See [#3298](https://github.com/clash-lang/clash-compiler/issues/3298).+* `flattenCallTree` now caches intermediate results, reducing Clash normalization by 10% for realistic designs. Fixes #[3246](https://github.com/clash-lang/clash-compiler/issues/3246).++Added:+* `-fclash-debug-manifest-hash`. When enabled, Clash emits a `__debug_hash` object in `clash-manifest.json` listing the SHA256 of each input that feeds into the top-level `hash` (`tops`, `prim_map`, `clash_mod_date`, `call_graph`, `opts`). As the name implies, this should only be used to debug and should not be relied upon by tooling. See [#3280](https://github.com/clash-lang/clash-compiler/pull/3280).+* `SaturatingNum` instances for `Erroring`, `Overflowing`, `Saturating`, `Wrapping`, and `Zeroing`.++Changed:+* Replaced the deprecated `data-binary-ieee754` dependency with `castDoubleToWord64`, `castFloatToWord32`, `castWord32ToFloat`, and `castWord64ToDouble` from `GHC.Float`. See [#3174](https://github.com/clash-lang/clash-compiler/issues/3174).+* `flake.nix` now advertises the [clash-lang Cachix binary cache](https://clash-lang.cachix.org) via `nixConfig.extra-substituters`. Running `nix develop` will prompt you to trust the cache, avoiding having to build Clash from source. See [#3213](https://github.com/clash-lang/clash-compiler/issues/3213).++Fixed:+* Clash no longer crashes for self-recursive global binders in very specific circumstances. See [#3311](https://github.com/clash-lang/clash-compiler/issues/3311).+* Clash no longer crashes upon calling `sequenceA`/`traverse#` on a zero-sized `Vec`. See [#3290](https://github.com/clash-lang/clash-compiler/issues/3290).+* Clash no longer crashes when constant-folding partial primitives in the GHC evaluator. This covers `shiftL`/`shiftR`/`rotateL`/`rotateR` with negative shift amounts on `BitVector`/`Signed`/`Unsigned`, `(^)` with negative exponents, `chr` on out-of-range integers, and `quot`/`rem`/`div`/`mod` by zero on `Int`/`Word`/`Int{8,16,32,64}`/`Word{8,16,32,64}`. Such expressions now fold to `undefined` (rather than crashing the compiler). Fixes [#3234](https://github.com/clash-lang/clash-compiler/issues/3234).+* Clash no longer crashes with `mkVecNil: failed to instantiate Nil DC` when unfolding `traverse#` in very specific circumstances. See [#3291](https://github.com/clash-lang/clash-compiler/issues/3291).+* Clash no longer errors when two `-i` import paths refer to the same directory via different syntactic spellings (e.g. `-isrc -isrc/.`) and a data file lives in that directory. See [#3142](https://github.com/clash-lang/clash-compiler/issues/3142).+* Clash no longer produces an error when using `dataToTag` in combination with custom bit representations. See [#2724](https://github.com/clash-lang/clash-compiler/issues/2724).+* Clash no longer takes exponential time and memory normalizing `foldl`/`scanl`/`splitAt` over a vector when the result keeps the (co-recursively defined) vector spine alive, e.g. `snd (foldl const (z, s) (xs :: Vec n a))`. The evaluator's `zipWith` and `splitAt` reductions now share their arguments instead of duplicating the vector spine on every peel. See [#3308](https://github.com/clash-lang/clash-compiler/issues/3308).+* Clash now recognizes `~` when solving GADT arms. Fixes [#3232](https://github.com/clash-lang/clash-compiler/issues/3232).+* Clash will no longer generate duplicate `attribute` when they're both used for top entity ports and internal signals. See [#3218](https://github.com/clash-lang/clash-compiler/issues/3218). The VHDL backend now also reports a clearer error when a synthesis attribute is declared with conflicting types in the same design.+* Due to HDL standards, when the result of a top entity is read by another binder Clash is forced to introduce an internal indirection signal. Clash no longer attaches the top entity's `Annotate` synthesis attributes to that internal signal, preventing duplicate synthesis attributes in the generated HDL. See [#3224](https://github.com/clash-lang/clash-compiler/issues/3224).+* Errors in `Synthesize` port annotations (e.g. a `PortProduct` on a non-product port) are now reported before a design is normalized, instead of afterwards. This avoids waiting for a potentially long normalization only to get a trivial port error. See [#3305](https://github.com/clash-lang/clash-compiler/issues/3305).+* Run `bindConstantVar` after post-normalization `inlineCleanup`/`caseCon` so constant let-bindings exposed late are inlined before netlist generation [#3041](https://github.com/clash-lang/clash-compiler/issues/3041).+* The VHDL primitives for `integerToNaturalThrow` and `integerToNaturalClamp` no longer contain syntax errors. See [#3315](https://github.com/clash-lang/clash-compiler/pull/3315).+* The internal function `Clash.Util.Interpolate.i` in `clash-lib` no longer inserts an extra blank line after a paragraph that gets reflowed onto multiple lines. See [#2753](https://github.com/clash-lang/clash-compiler/issues/2753).+* `deriveAutoReg` no longer fails on GHC versions where `KnownNat` lives in `GHC.Internal.TypeNats` rather than `GHC.TypeNats`. See [#3100](https://github.com/clash-lang/clash-compiler/issues/3100).+* `makeTopEntity` now accounts for unary product types. See [#3066](https://github.com/clash-lang/clash-compiler/issues/3066).+ ## 1.10.0 *Apr 23rd, 2026* Release highlight:
clash-prelude.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.2 Name: clash-prelude-Version: 1.10.0+Version: 1.10.1 Synopsis: Clash: a functional hardware description language - Prelude library Description: Clash is a functional hardware description language that borrows both its@@ -277,6 +277,7 @@ Clash.Sized.Vector.ToTuple.TH Clash.Sized.Internal.BitVector+ Clash.Sized.Internal.CheckedLiterals Clash.Sized.Internal.Index Clash.Sized.Internal.Mod Clash.Sized.Internal.Signed@@ -328,7 +329,6 @@ bytestring >= 0.10.8 && < 0.13, constraints >= 0.9 && < 1.0, containers >= 0.4.0 && < 0.9,- data-binary-ieee754 >= 0.4.4 && < 0.6, data-default >= 0.7 && < 0.9, deepseq >= 1.4.1.0 && < 1.6, distributive >= 0.1 && < 1.0,@@ -342,18 +342,19 @@ half >= 0.2.2.3 && < 1.0, infinite-list ^>= 0.1, lens >= 4.10 && < 5.4,- QuickCheck >= 2.7 && < 2.16,+ QuickCheck >= 2.7 && < 2.19, recursion-schemes >= 5.1 && < 5.3, reflection >= 2 && < 2.2,+ checked-literals >= 0.1.1 && < 0.2, singletons >= 2.0 && < 3.1,- string-interpolate ^>= 0.3,+ string-interpolate >= 0.3 && < 1.1, tagged >= 0.8 && < 0.9, template-haskell >= 2.20.0.0 && < 2.24, th-abstraction >= 0.3.0 && < 0.8.0, th-lift >= 0.7.0 && < 0.9, th-orphans >= 0.13.1 && < 1.0, text >= 0.11.3.1 && < 2.2,- time >= 1.8 && < 1.15,+ time >= 1.8 && < 1.17, transformers >= 0.5.2.0 && < 0.7, type-errors >= 0.2.0.0 && < 0.3, uniplate >= 1.6.12 && < 1.7,@@ -402,6 +403,7 @@ else build-depends: clash-prelude,+ checked-literals, ghc-typelits-knownnat, ghc-typelits-natnormalise,@@ -412,16 +414,19 @@ bytestring, containers, deepseq,- hedgehog >= 1.0.3 && < 1.6,+ hedgehog >= 1.0.3 && < 1.8, hint >= 0.7 && < 0.10, mmorph >= 1.1.5 && < 1.3,+ process, quickcheck-classes-base >= 0.6 && < 1.0,+ string-interpolate >=0.3.4.0, tasty >= 1.2 && < 1.6, tasty-hedgehog >= 1.2.0, tasty-hunit, tasty-th, tasty-quickcheck, template-haskell,+ temporary, text Other-Modules:@@ -431,6 +436,15 @@ Clash.Tests.BitVector Clash.Tests.BlockRam Clash.Tests.BlockRam.Blob+ Clash.Tests.CheckedLiterals+ Clash.Tests.CheckedLiterals.BitVector+ Clash.Tests.CheckedLiterals.Common+ Clash.Tests.CheckedLiterals.Fixed+ Clash.Tests.CheckedLiterals.Index+ Clash.Tests.CheckedLiterals.Signals+ Clash.Tests.CheckedLiterals.Signed+ Clash.Tests.CheckedLiterals.Unsigned+ Clash.Tests.CheckedLiterals.Wrappers Clash.Tests.Clocks Clash.Tests.Counter Clash.Tests.DumpVCD@@ -461,6 +475,7 @@ Hedgehog.Extra + Test.Tasty.AssertGhc Test.Tasty.HUnit.Extra Test.Tasty.Hedgehog.Extra Test.QuickCheck.Extra
src/Clash/Annotations/TH.hs view
@@ -255,6 +255,7 @@ = c >>= \case Complete [] -> return $ Complete [PortName name] Complete [PortName n2] -> return $ Complete [PortName (name ++ "_" ++ n2)]+ Complete [PortProduct "" ys] -> return $ Complete [PortProduct name ys] Complete xs -> return $ Complete [PortProduct name xs] x -> return x
src/Clash/Class/AutoReg/Internal.hs view
@@ -341,7 +341,7 @@ constraintsWantedFor :: Name -> [Type] -> Q Cxt constraintsWantedFor clsNm tys- | show clsNm == "GHC.TypeNats.KnownNat" = do+ | clsNm == ''KnownNat = do -- KnownNat is special, you can't just lookup instances with reifyInstances. -- So we just pass KnownNat constraints. -- This will most likely require UndecidableInstances.
src/Clash/Class/BitPack/Internal.hs view
@@ -27,8 +27,8 @@ import Prelude hiding (map) -import Data.Binary.IEEE754 (doubleToWord, floatToWord, wordToDouble,- wordToFloat)+import GHC.Float (castDoubleToWord64, castFloatToWord32,+ castWord32ToFloat, castWord64ToDouble) import Data.Char (chr, ord) import Data.Complex (Complex)@@ -398,12 +398,12 @@ unpack = checkUnpackUndef unpackFloat# packFloat# :: Float -> BitVector 32-packFloat# = fromIntegral . floatToWord+packFloat# = fromIntegral . castFloatToWord32 {-# OPAQUE packFloat# #-} {-# ANN packFloat# hasBlackBox #-} unpackFloat# :: BitVector 32 -> Float-unpackFloat# (unsafeToNatural -> w) = wordToFloat (fromIntegral w)+unpackFloat# (unsafeToNatural -> w) = castWord32ToFloat (fromIntegral w) {-# OPAQUE unpackFloat# #-} {-# ANN unpackFloat# hasBlackBox #-} @@ -413,12 +413,12 @@ unpack = checkUnpackUndef unpackDouble# packDouble# :: Double -> BitVector 64-packDouble# = fromIntegral . doubleToWord+packDouble# = fromIntegral . castDoubleToWord64 {-# OPAQUE packDouble# #-} {-# ANN packDouble# hasBlackBox #-} unpackDouble# :: BitVector 64 -> Double-unpackDouble# (unsafeToNatural -> w) = wordToDouble (fromIntegral w)+unpackDouble# (unsafeToNatural -> w) = castWord64ToDouble (fromIntegral w) {-# OPAQUE unpackDouble# #-} {-# ANN unpackDouble# hasBlackBox #-}
src/Clash/Num/Erroring.hs view
@@ -1,11 +1,12 @@-{--Copyright : (C) 2021, QBayLogic B.V.+{-|+Copyright : (C) 2021-2026, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Clash.Num.Erroring ( Erroring@@ -20,6 +21,14 @@ import Data.Functor.Compose (Compose(..)) import Data.Hashable (Hashable) import GHC.TypeLits (KnownNat, type (+))+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Test.QuickCheck (Arbitrary) import Clash.Class.BitPack (BitPack)@@ -57,6 +66,22 @@ toErroring :: (SaturatingNum a) => a -> Erroring a toErroring = Erroring +instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Erroring a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Erroring a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Erroring a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Erroring a)+ instance (Resize f) => Resize (Compose Erroring f) where {-# INLINE resize #-} resize@@ -110,6 +135,22 @@ -- is not in range (typically wrapping). It would be better if this also -- threw an XException, but in a way which remained synthesizable. fromInteger = coerce (fromInteger @a)++instance (Ord a, SaturatingNum a) => SaturatingNum (Erroring a) where+ {-# INLINE satAdd #-}+ satAdd mode (Erroring a) (Erroring b) = Erroring $ satAdd mode a b++ {-# INLINE satSub #-}+ satSub mode (Erroring a) (Erroring b) = Erroring $ satSub mode a b++ {-# INLINE satMul #-}+ satMul mode (Erroring a) (Erroring b) = Erroring $ satMul mode a b++ {-# INLINE satSucc #-}+ satSucc mode (Erroring a) = Erroring $ satSucc mode a++ {-# INLINE satPred #-}+ satPred mode (Erroring a) = Erroring $ satPred mode a instance (Enum a, SaturatingNum a) => Enum (Erroring a) where {-# INLINE succ #-}
src/Clash/Num/Overflowing.hs view
@@ -1,11 +1,13 @@ {-|-Copyright : (C) 2021-2022, QBayLogic B.V.+Copyright : (C) 2021-2026, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} @@ -25,6 +27,14 @@ import Data.Hashable (Hashable) import GHC.Generics (Generic) import GHC.TypeLits (KnownNat, type (+))+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Clash.Class.BitPack (BitPack(..)) import Clash.Class.Num (SaturationMode(SatWrap, SatZero), SaturatingNum(..))@@ -55,6 +65,22 @@ clearOverflow :: Overflowing a -> Overflowing a clearOverflow x = x { hasOverflowed = False } +instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Overflowing a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Overflowing a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Overflowing a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Overflowing a)+ instance (Eq a) => Eq (Overflowing a) where {-# INLINE (==) #-} (==) = (==) `on` fromOverflowing@@ -138,6 +164,75 @@ instance (Bounded a) => Bounded (Overflowing a) where minBound = Overflowing minBound False maxBound = Overflowing maxBound False++-- | NOTE: Usage of this instance might introduce redundant circuitry+-- for the overflow check (depending on the utilized 'SaturationMode'+-- or inner type), which is not guaranteed to be optimized away at a+-- later synthesis stage.+--+-- The 'hasOverflowed' flag still will be set even when the 'SaturatingNum'+-- operation has prevented the overflow:+-- @hasOverflowed (satSucc SatBound maxBound) == True@+instance (Ord a, SaturatingNum a) => SaturatingNum (Overflowing a) where+ {-# INLINE satAdd #-}+ satAdd mode (Overflowing x a) (Overflowing y b)+ | y > 0+ , x > satSub SatWrap maxBound y+ = withOverflow True++ | y < 0+ , x < satSub SatWrap minBound y+ = withOverflow True++ | otherwise+ = withOverflow (a || b)+ where+ withOverflow =+ let r = satAdd mode x y+ in seq r $ Overflowing r++ {-# INLINE satSub #-}+ satSub mode (Overflowing x a) (Overflowing y b)+ | y < 0+ , x > satAdd SatWrap maxBound y+ = withOverflow True++ | y > 0+ , x < satAdd SatWrap minBound y+ = withOverflow True++ | otherwise+ = withOverflow (a || b)+ where+ withOverflow =+ let r = satSub mode x y+ in seq r $ Overflowing r++ {-# INLINE satMul #-}+ satMul mode (Overflowing x a) (Overflowing y b)+ | x /= 0+ , y /= 0+ , satMul SatZero x y == 0+ = withOverflow True++ | otherwise+ = withOverflow (a || b)+ where+ withOverflow =+ let r = satMul mode x y+ in seq r $ Overflowing r++ {-# INLINE satSucc #-}+ satSucc mode (Overflowing x a) =+ let xSucc = satSucc mode x+ in seq xSucc+ $ Overflowing xSucc (a || x == maxBound)++ {-# INLINE satPred #-}+ satPred mode (Overflowing x a) =+ let xPred = satPred mode x+ in seq xPred+ $ Overflowing (satPred mode x) (a || x == minBound) instance (Enum a, Eq a, SaturatingNum a) => Enum (Overflowing a) where succ (Overflowing x a)
src/Clash/Num/Saturating.hs view
@@ -1,11 +1,12 @@-{--Copyright : (C) 2021, QBayLogic B.V.+{-|+Copyright : (C) 2021-2026, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Clash.Num.Saturating ( Saturating@@ -20,6 +21,14 @@ import Data.Functor.Compose (Compose(..)) import Data.Hashable (Hashable) import GHC.TypeLits (KnownNat, type (+))+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Test.QuickCheck (Arbitrary) import Clash.Class.BitPack (BitPack)@@ -57,6 +66,22 @@ toSaturating :: (SaturatingNum a) => a -> Saturating a toSaturating = Saturating +instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Saturating a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Saturating a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Saturating a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Saturating a)+ instance (Resize f) => Resize (Compose Saturating f) where {-# INLINE resize #-} resize@@ -109,6 +134,22 @@ -- is not in range (typically wrapping). It would be better if this also -- saturated, but in a way which remained synthesizable. fromInteger = coerce (fromInteger @a)++instance (Ord a, SaturatingNum a) => SaturatingNum (Saturating a) where+ {-# INLINE satAdd #-}+ satAdd mode (Saturating a) (Saturating b) = Saturating $ satAdd mode a b++ {-# INLINE satSub #-}+ satSub mode (Saturating a) (Saturating b) = Saturating $ satSub mode a b++ {-# INLINE satMul #-}+ satMul mode (Saturating a) (Saturating b) = Saturating $ satMul mode a b++ {-# INLINE satSucc #-}+ satSucc mode (Saturating a) = Saturating $ satSucc mode a++ {-# INLINE satPred #-}+ satPred mode (Saturating a) = Saturating $ satPred mode a instance (Enum a, SaturatingNum a) => Enum (Saturating a) where {-# INLINE succ #-}
src/Clash/Num/Wrapping.hs view
@@ -6,6 +6,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Clash.Num.Wrapping ( Wrapping(..)@@ -19,6 +20,14 @@ import Data.Functor.Compose (Compose(..)) import Data.Hashable (Hashable) import GHC.TypeLits (KnownNat, type (+))+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Test.QuickCheck (Arbitrary) import Clash.Class.BitPack (BitPack)@@ -56,6 +65,22 @@ toWrapping :: (SaturatingNum a) => a -> Wrapping a toWrapping = Wrapping +instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Wrapping a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Wrapping a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Wrapping a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Wrapping a)+ instance (Resize f) => Resize (Compose Wrapping f) where {-# INLINE resize #-} resize@@ -107,6 +132,22 @@ -- is not in range (typically wrapping). It would be better if this also -- definitely wrapped, but in a way which remained synthesizable. fromInteger = coerce (fromInteger @a)++instance (Bounded a, SaturatingNum a) => SaturatingNum (Wrapping a) where+ {-# INLINE satAdd #-}+ satAdd mode (Wrapping a) (Wrapping b) = Wrapping $ satAdd mode a b++ {-# INLINE satSub #-}+ satSub mode (Wrapping a) (Wrapping b) = Wrapping $ satSub mode a b++ {-# INLINE satMul #-}+ satMul mode (Wrapping a) (Wrapping b) = Wrapping $ satMul mode a b++ {-# INLINE satSucc #-}+ satSucc mode (Wrapping a) = Wrapping $ satSucc mode a++ {-# INLINE satPred #-}+ satPred mode (Wrapping a) = Wrapping $ satPred mode a instance (Enum a, SaturatingNum a) => Enum (Wrapping a) where {-# INLINE succ #-}
src/Clash/Num/Zeroing.hs view
@@ -1,11 +1,12 @@-{--Copyright : (C) 2021, QBayLogic B.V.+{-|+Copyright : (C) 2021-2026, QBayLogic B.V. License : BSD2 (see the file LICENSE) Maintainer : QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE MultiParamTypeClasses #-} module Clash.Num.Zeroing ( Zeroing@@ -20,6 +21,14 @@ import Data.Functor.Compose (Compose(..)) import Data.Hashable (Hashable) import GHC.TypeLits (KnownNat, type (+))+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Test.QuickCheck (Arbitrary) import Clash.Class.BitPack (BitPack)@@ -56,6 +65,22 @@ toZeroing :: (SaturatingNum a) => a -> Zeroing a toZeroing = Zeroing +instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Zeroing a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Zeroing a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Zeroing a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Zeroing a)+ instance (Resize f) => Resize (Compose Zeroing f) where {-# INLINE resize #-} resize@@ -108,6 +133,22 @@ -- is not in range (typically wrapping). It would be better if this also -- returned zero, but in a way which remained synthesizable. fromInteger = coerce (fromInteger @a)++instance (Ord a, SaturatingNum a) => SaturatingNum (Zeroing a) where+ {-# INLINE satAdd #-}+ satAdd mode (Zeroing a) (Zeroing b) = Zeroing $ satAdd mode a b++ {-# INLINE satSub #-}+ satSub mode (Zeroing a) (Zeroing b) = Zeroing $ satSub mode a b++ {-# INLINE satMul #-}+ satMul mode (Zeroing a) (Zeroing b) = Zeroing $ satMul mode a b++ {-# INLINE satSucc #-}+ satSucc mode (Zeroing a) = Zeroing $ satSucc mode a++ {-# INLINE satPred #-}+ satPred mode (Zeroing a) = Zeroing $ satPred mode a instance (Enum a, SaturatingNum a) => Enum (Zeroing a) where {-# INLINE succ #-}
src/Clash/Signal/Delayed/Internal.hs view
@@ -7,6 +7,7 @@ Maintainer : QBayLogic B.V. <devops@qbaylogic.com> -} {-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}@@ -38,6 +39,14 @@ import Data.Default (Default(..)) import GHC.TypeLits (Nat, type (+)) import Language.Haskell.TH.Syntax (Lift)+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import Test.QuickCheck (Arbitrary, CoArbitrary) import Clash.Promoted.Nat (SNat)@@ -106,6 +115,22 @@ } deriving ( Show, Default, Functor, Applicative, Num, Fractional , Foldable, Traversable, Arbitrary, CoArbitrary, Lift )++instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (DSignal dom delay a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (DSignal dom delay a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (DSignal dom delay a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (DSignal dom delay a) -- | Create a 'DSignal' from a list --
src/Clash/Signal/Internal.hs view
@@ -15,6 +15,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE RoleAnnotations #-}@@ -210,6 +211,14 @@ import Language.Haskell.TH.Syntax -- (Lift (..), Q, Dec) import Language.Haskell.TH.Compat import Numeric.Natural (Natural)+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ ) import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO) import Test.QuickCheck (Arbitrary (..), CoArbitrary(..), Property, property)@@ -915,6 +924,22 @@ abs = fmap abs signum = fmap signum fromInteger = signal# . fromInteger++instance+ (CheckedPositiveIntegerLiteral lit a) =>+ CheckedPositiveIntegerLiteral lit (Signal dom a)++instance+ (CheckedNegativeIntegerLiteral lit a) =>+ CheckedNegativeIntegerLiteral lit (Signal dom a)++instance+ (CheckedPositiveRationalLiteral str num den a) =>+ CheckedPositiveRationalLiteral str num den (Signal dom a)++instance+ (CheckedNegativeRationalLiteral str num den a) =>+ CheckedNegativeRationalLiteral str num den (Signal dom a) instance Bounded a => Bounded (Signal dom a) where minBound = pure minBound
src/Clash/Sized/BitVector.hs view
@@ -34,6 +34,9 @@ , (.<<+) -- ** Pattern matching , bitPattern+ -- * Type-level error messages+ , BitPositiveLiteralError+ , BitVectorPositiveLiteralError ) where
src/Clash/Sized/Fixed.hs view
@@ -68,6 +68,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NegativeLiterals #-}@@ -106,6 +107,20 @@ , NumFixedC, ENumFixedC, FracFixedC, ResizeFC, DivideC -- * Proxy , asRepProxy, asIntProxy+ -- * Type-level error messages+ , UFixedPositiveLiteralError+ , UFixedNegativeLiteralError+ , SFixedPositiveLiteralError+ , SFixedNegativeLiteralError+ , SFixedPositiveRationalRequiredIntBits+ , SFixedNegativeRationalRequiredIntBits+ , SFixedPositiveRationalLiteralError+ , SFixedNegativeRationalLiteralError+ , FitsPositiveSFixedRational+ , FitsNegativeSFixedRational+ , CheckFixedFrac+ , FixedPointNotPow2Error+ , FixedPointNotEnoughFracError ) where @@ -115,14 +130,27 @@ import Data.Data (Data) import Data.Default (Default (..)) import Data.Either (isLeft)-import Data.Kind (Type)+import Data.Kind (Constraint, Type) import Text.Read (Read(..)) import Data.List (find) import Data.Proxy (Proxy (..)) import Data.Ratio ((%), denominator, numerator)+import Data.Type.Bool (If) import Data.Typeable (Typeable, TypeRep, typeRep, typeOf)-import GHC.TypeLits (KnownNat, Nat, type (+), natVal)-import GHC.TypeLits.Extra (Max)+import GHC.TypeError+ ( Assert+ , ErrorMessage (ShowType, Text, (:<>:))+ )+import GHC.TypeLits+ ( Div+ , KnownNat+ , Nat+ , natVal+ , type (+)+ , type (-)+ , type (<=?)+ )+import GHC.TypeLits.Extra (CLog, Max) import Language.Haskell.TH (Q, appT, conT, litT, mkName, numTyLit, sigE) import Language.Haskell.TH.Syntax (Lift(..))@@ -141,7 +169,25 @@ import Clash.Class.BitPack.BitReduction (reduceAnd, reduceOr) import Clash.Sized.BitVector (BitVector, (++#)) import Clash.Sized.Signed (Signed)+import Clash.Sized.Internal.CheckedLiterals+ ( FractionalBitsNote+ , IntegerBitsNote+ , NotExactlyRepresentable+ , NotExactlyRepresentableWithConstraint+ , OutOfBoundsBecause+ , PotentiallyOutOfBounds+ , SignedIntegerBitsNote+ ) import Clash.Sized.Unsigned (Unsigned)+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ )+import CheckedLiterals.Class.Rational+ ( CheckedNegativeRationalLiteral+ , CheckedPositiveRationalLiteral+ )+import CheckedLiterals.Class.Rational.TypeNats (IsPowerOfTwo) import Clash.XException (ShowX (..), NFDataX (..), isX, errorX, showsPrecXWith, fromJustX) @@ -223,6 +269,21 @@ -- -5.0 type SFixed = Fixed Signed +type SFixedPositiveRationalRequiredIntBits (num :: Nat) (den :: Nat) =+ CLog 2 (num + 1) + 1 - CLog 2 den++type SFixedNegativeRationalRequiredIntBits (num :: Nat) (den :: Nat) =+ CLog 2 num + 1 - CLog 2 den++type family FitsPositiveSFixedRational (num :: Nat) (den :: Nat) (int :: Nat) :: Bool where+ FitsPositiveSFixedRational 0 den int = 'True+ FitsPositiveSFixedRational num den int =+ SFixedPositiveRationalRequiredIntBits num den <=? int++type family FitsNegativeSFixedRational (num :: Nat) (den :: Nat) (int :: Nat) :: Bool where+ FitsNegativeSFixedRational num den int =+ SFixedNegativeRationalRequiredIntBits num den <=? int+ -- | Unsigned 'Fixed'-point number, with @int@ integer bits and @frac@ -- fractional bits --@@ -253,6 +314,126 @@ -- >>> (1 :: UFixed 3 4) `sub` (3 :: UFixed 3 4) :: UFixed 4 4 -- 14.0 type UFixed = Fixed Unsigned++type UFixedPositiveLiteralError strLit lit int =+ PotentiallyOutOfBounds+ strLit+ (IntegerBitsNote (CLog 2 (lit + 1)))+ (CLog 2 (lit + 1))+ int++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 (lit + 1) <=? int))+ (UFixedPositiveLiteralError (ShowType lit) lit int)+ ) =>+ CheckedPositiveIntegerLiteral lit (UFixed int frac)++type UFixedNegativeLiteralError strLit =+ OutOfBoundsBecause+ strLit+ ('Text "UFixed cannot represent negative numbers.")++instance+ (UFixedNegativeLiteralError ('Text "-" ':<>: 'ShowType lit)) =>+ CheckedNegativeIntegerLiteral lit (UFixed int frac)++type FixedPointNotPow2Error strLit den typ =+ NotExactlyRepresentable+ strLit+ typ+ ( 'Text "The reduced denominator "+ ':<>: 'ShowType den+ ':<>: 'Text " is not a power of 2."+ )++type FixedPointNotEnoughFracError strLit den frac typ =+ NotExactlyRepresentableWithConstraint+ strLit+ typ+ (FractionalBitsNote (CLog 2 den))+ (CLog 2 den)+ frac++type family+ CheckFixedFrac (isPow2 :: Bool) (strLit :: ErrorMessage) (den :: Nat) (frac :: Nat) (typ :: Type) ::+ Constraint+ where+ CheckFixedFrac 'False strLit den frac typ = FixedPointNotPow2Error strLit den typ+ CheckFixedFrac 'True strLit den frac typ =+ Assert+ (CLog 2 den <=? frac)+ (FixedPointNotEnoughFracError strLit den frac typ)++instance+ ( Assert+ (If (Div num den <=? 0) (Div num den <=? 0) (CLog 2 (Div num den + 1) <=? int))+ (UFixedPositiveLiteralError ('Text str) (Div num den) int)+ , CheckFixedFrac (IsPowerOfTwo den) ('Text str) den frac (UFixed int frac)+ ) =>+ CheckedPositiveRationalLiteral str num den (UFixed int frac)++instance+ (UFixedNegativeLiteralError ('Text str)) =>+ CheckedNegativeRationalLiteral str num den (UFixed int frac)++type SFixedPositiveLiteralError strLit lit int =+ PotentiallyOutOfBounds+ strLit+ (SignedIntegerBitsNote (CLog 2 (lit + 1) + 1))+ (CLog 2 (lit + 1) + 1)+ int++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 (lit + 1) + 1 <=? int))+ (SFixedPositiveLiteralError (ShowType lit) lit int)+ ) =>+ CheckedPositiveIntegerLiteral lit (SFixed int frac)++type SFixedNegativeLiteralError strLit lit int =+ PotentiallyOutOfBounds+ strLit+ (SignedIntegerBitsNote (CLog 2 lit + 1))+ (CLog 2 lit + 1)+ int++type SFixedPositiveRationalLiteralError strLit num den int =+ PotentiallyOutOfBounds+ strLit+ (SignedIntegerBitsNote (SFixedPositiveRationalRequiredIntBits num den))+ (SFixedPositiveRationalRequiredIntBits num den)+ int++type SFixedNegativeRationalLiteralError strLit num den int =+ PotentiallyOutOfBounds+ strLit+ (SignedIntegerBitsNote (SFixedNegativeRationalRequiredIntBits num den))+ (SFixedNegativeRationalRequiredIntBits num den)+ int++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 lit + 1 <=? int))+ (SFixedNegativeLiteralError ('Text "-" ':<>: 'ShowType lit) lit int)+ ) =>+ CheckedNegativeIntegerLiteral lit (SFixed int frac)++instance+ ( CheckFixedFrac (IsPowerOfTwo den) ('Text str) den frac (SFixed int frac)+ , Assert+ (FitsPositiveSFixedRational num den int)+ (SFixedPositiveRationalLiteralError ('Text str) num den int)+ ) =>+ CheckedPositiveRationalLiteral str num den (SFixed int frac)++instance+ ( CheckFixedFrac (IsPowerOfTwo den) ('Text str) den frac (SFixed int frac)+ , Assert+ (FitsNegativeSFixedRational num den int)+ (SFixedNegativeRationalLiteralError ('Text str) num den int)+ ) =>+ CheckedNegativeRationalLiteral str num den (SFixed int frac) {-# INLINE sf #-} -- | Treat a 'Signed' integer as a @Signed@ 'Fixed'-@point@ integer
src/Clash/Sized/Index.hs view
@@ -13,7 +13,10 @@ {-# OPTIONS_HADDOCK show-extensions #-} module Clash.Sized.Index- (Index, bv2i, fromSNat)+ ( Index, bv2i, fromSNat+ -- * Type-level error messages+ , IndexPositiveLiteralError+ ) where import GHC.TypeLits (KnownNat, type (^))
src/Clash/Sized/Internal/BitVector.hs view
@@ -11,6 +11,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RoleAnnotations #-}@@ -30,6 +31,8 @@ -- ** Construction , high , low+ -- ** Type-level error messages+ , BitPositiveLiteralError -- ** Type classes -- *** Eq , eq##@@ -127,6 +130,8 @@ , truncateB# -- *** QuickCheck , shrinkSizedUnsigned+ -- ** Type-level error messages+ , BitVectorPositiveLiteralError -- ** Other , undefError , checkUnpackUndef@@ -143,6 +148,7 @@ import Data.Default (Default (..)) import Data.Either (isLeft) import Data.Proxy (Proxy (..))+import Data.Type.Bool (If) import Data.Typeable (Typeable, typeOf) import GHC.Generics (Generic) import Data.Maybe (fromMaybe)@@ -156,9 +162,20 @@ (Natural (..), naturalFromWord, naturalShiftL, naturalShiftR, naturalToWord) import GHC.Natural (naturalToInteger) import GHC.Stack (withFrozenCallStack)-import GHC.TypeLits (KnownNat, Nat, type (+), type (-))+import GHC.TypeError+ ( Assert+ , ErrorMessage (ShowType)+ )+import GHC.TypeLits+ ( KnownNat+ , Nat+ , type (+)+ , type (-)+ , type (<=?)+ , type (^)+ ) import GHC.TypeNats (natVal)-import GHC.TypeLits.Extra (Max)+import GHC.TypeLits.Extra (CLog, Max) import Language.Haskell.TH (Lit (..), ExpQ, Type(ConT, AppT, LitT), Exp(VarE, AppE, SigE, LitE), TyLit(NumTyLit), Pat, Q, appT, conT, litE, litP, litT, mkName, numTyLit,@@ -178,10 +195,20 @@ import Clash.Promoted.Nat (SNat (..), SNatLE (..), compareSNat, snatToInteger, snatToNum, natToNum) import Clash.Sized.Internal (formatRange)+import Clash.Sized.Internal.CheckedLiterals+ ( OutOfBounds+ , PotentiallyOutOfBounds+ , UnsignedBounds+ ) import Clash.XException (ShowX (..), NFDataX (..), errorX, isX, showsPrecXWith, rwhnfX, XException(..)) import Clash.Sized.Internal.Mod+import CheckedLiterals.Class.Integer+ ( NegativeUnsignedError+ , CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ ) import {-# SOURCE #-} qualified Clash.Sized.Vector as V import {-# SOURCE #-} qualified Clash.Sized.Internal.Index as I@@ -390,6 +417,17 @@ countLeadingZeros b = if eq## b low then 1 else 0 countTrailingZeros b = if eq## b low then 1 else 0 +type BitPositiveLiteralError lit =+ OutOfBounds ('ShowType lit) (UnsignedBounds Bit 1)++instance+ (Assert (lit <=? 1) (BitPositiveLiteralError lit)) =>+ CheckedPositiveIntegerLiteral lit Bit++instance+ (NegativeUnsignedError lit Bit 1) =>+ CheckedNegativeIntegerLiteral lit Bit+ and##, or##, xor## :: Bit -> Bit -> Bit and## (Bit m1 v1) (Bit m2 v2) = Bit mask (v1 .&. v2 .&. complement mask) where mask = (m1.&.v2 .|. m1.&.m2 .|. m2.&.v1)@@ -855,6 +893,24 @@ finiteBitSize = size# countLeadingZeros = fromInteger . I.toInteger# . countLeadingZerosBV countTrailingZeros = fromInteger . I.toInteger# . countTrailingZerosBV++type BitVectorPositiveLiteralError lit n =+ PotentiallyOutOfBounds+ ('ShowType lit)+ (UnsignedBounds (BitVector n) ((2 ^ n) - 1))+ (CLog 2 (lit + 1))+ n++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 (lit + 1) <=? n))+ (BitVectorPositiveLiteralError lit n)+ ) =>+ CheckedPositiveIntegerLiteral lit (BitVector n)++instance+ (NegativeUnsignedError lit (BitVector n) ((2 ^ n) - 1)) =>+ CheckedNegativeIntegerLiteral lit (BitVector n) countLeadingZerosBV :: KnownNat n => BitVector n -> I.Index (n+1) countLeadingZerosBV = V.foldr (\l r -> if eq## l low then 1 + r else 0) 0 . V.bv2v
+ src/Clash/Sized/Internal/CheckedLiterals.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE NoStarIsType #-}+{-# LANGUAGE TypeOperators #-}++module Clash.Sized.Internal.CheckedLiterals where++import Data.Kind (Type)+import GHC.TypeError+ ( ErrorMessage (ShowType, Text, (:$$:), (:<>:))+ , TypeError+ )++type CheckedLiteralUncheckedFix =+ 'Text "Possible fix: use 'uncheckedLiteral' from 'CheckedLiterals' to bypass this check."++type AddConstraintFix required actual =+ 'Text "Possible fix: add a constraint: "+ ':<>: 'ShowType required+ ':<>: 'Text " <= "+ ':<>: 'ShowType actual+ ':<>: 'Text "."++type UnsignedBounds (typ :: Type) maxVal =+ 'ShowType typ+ ':<>: 'Text " has bounds: [0 .. "+ ':<>: 'ShowType maxVal+ ':<>: 'Text "]."++type SignedBounds (typ :: Type) minVal maxVal =+ 'ShowType typ+ ':<>: 'Text " has bounds: [-"+ ':<>: 'ShowType minVal+ ':<>: 'Text " .. "+ ':<>: 'ShowType maxVal+ ':<>: 'Text "]."++type IntegerBitsNote bits =+ 'Text "Note: integer part needs at least "+ ':<>: 'ShowType bits+ ':<>: 'Text " bit(s)."++type SignedIntegerBitsNote bits =+ 'Text "Note: integer part needs at least "+ ':<>: 'ShowType bits+ ':<>: 'Text " bit(s), including sign bit."++type FractionalBitsNote bits =+ 'Text "The fractional part needs at least "+ ':<>: 'ShowType bits+ ':<>: 'Text " bit(s)."++type OutOfBounds strLit details =+ TypeError+ ( 'Text "Literal "+ ':<>: strLit+ ':<>: 'Text " is out of bounds."+ ':$$: details+ ':$$: CheckedLiteralUncheckedFix+ )++type PotentiallyOutOfBounds strLit details required actual =+ TypeError+ ( 'Text "Literal "+ ':<>: strLit+ ':<>: 'Text " is (potentially) out of bounds."+ ':$$: details+ ':$$: AddConstraintFix required actual+ ':$$: CheckedLiteralUncheckedFix+ )++type OutOfBoundsBecause strLit reason =+ TypeError+ ( 'Text "Literal "+ ':<>: strLit+ ':<>: 'Text " is out of bounds, because "+ ':<>: reason+ ':$$: CheckedLiteralUncheckedFix+ )++type NotExactlyRepresentable strLit (typ :: Type) reason =+ TypeError+ ( 'Text "Literal "+ ':<>: strLit+ ':<>: 'Text " cannot be represented exactly by "+ ':<>: 'ShowType typ+ ':<>: 'Text "."+ ':$$: reason+ ':$$: CheckedLiteralUncheckedFix+ )++type NotExactlyRepresentableWithConstraint strLit (typ :: Type) reason required actual =+ TypeError+ ( 'Text "Literal "+ ':<>: strLit+ ':<>: 'Text " cannot be represented exactly by "+ ':<>: 'ShowType typ+ ':<>: 'Text "."+ ':$$: reason+ ':$$: AddConstraintFix required actual+ ':$$: CheckedLiteralUncheckedFix+ )
src/Clash/Sized/Internal/Index.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RoleAnnotations #-} {-# LANGUAGE TemplateHaskell #-}@@ -68,6 +69,8 @@ , toInteger# -- ** Resize , resize#+ -- * Type-level error messages+ , IndexPositiveLiteralError ) where @@ -88,8 +91,20 @@ import GHC.Natural (Natural, naturalFromInteger) import GHC.Natural (naturalToInteger) import GHC.Stack (HasCallStack)-import GHC.TypeLits (KnownNat, Nat, type (+), type (-),- type (*), type (<=), natVal)+import GHC.TypeError+ ( Assert+ , ErrorMessage (ShowType)+ )+import GHC.TypeLits+ ( KnownNat+ , Nat+ , natVal+ , type (+)+ , type (-)+ , type (*)+ , type (<=)+ , type (<=?)+ ) import GHC.TypeLits.Extra (CLogWZ) import Test.QuickCheck.Arbitrary (Arbitrary (..), CoArbitrary (..), arbitraryBoundedIntegral,@@ -103,9 +118,18 @@ import Clash.Class.Resize (Resize (..)) import Clash.Class.BitPack.BitIndex (replaceBit) import Clash.Sized.Internal (formatRange)+import Clash.Sized.Internal.CheckedLiterals+ ( PotentiallyOutOfBounds+ , UnsignedBounds+ ) import {-# SOURCE #-} Clash.Sized.Internal.BitVector (BitVector (BV), high, low, undefError) import qualified Clash.Sized.Internal.BitVector as BV import Clash.Promoted.Nat (SNat(..), UNat(..), toUNat, snatToNum, natToInteger)+import CheckedLiterals.Class.Integer+ ( NegativeUnsignedError+ , CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ ) import Clash.XException (ShowX (..), NFDataX (..), errorX, showsPrecXWith, rwhnfX, seqX) @@ -287,6 +311,24 @@ abs = id signum i = if i == 0 then 0 else 1 fromInteger = fromInteger#++type IndexPositiveLiteralError lit n =+ PotentiallyOutOfBounds+ ('ShowType lit)+ (UnsignedBounds (Index n) (n - 1))+ (lit + 1)+ n++instance+ ( Assert+ (lit + 1 <=? n)+ (IndexPositiveLiteralError lit n)+ ) =>+ CheckedPositiveIntegerLiteral lit (Index n)++instance+ (NegativeUnsignedError lit (Index n) (n - 1)) =>+ CheckedNegativeIntegerLiteral lit (Index n) (+#),(-#),(*#) :: KnownNat n => Index n -> Index n -> Index n {-# OPAQUE (+#) #-}
src/Clash/Sized/Internal/Signed.hs view
@@ -8,6 +8,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RoleAnnotations #-}@@ -81,6 +82,9 @@ , truncateB# -- ** SaturatingNum , minBoundSym#+ -- * Type-level error messages+ , SignedPositiveLiteralError+ , SignedNegativeLiteralError ) where @@ -92,13 +96,26 @@ import Data.Data (Data) import Data.Default (Default (..)) import Data.Proxy (Proxy (..))+import Data.Type.Bool (If) import Text.Read (Read (..), ReadPrec) import Text.Printf (PrintfArg (..), printf) import GHC.Generics (Generic) import GHC.Natural (naturalFromInteger, naturalToInteger) -import GHC.TypeLits (KnownNat, Nat, type (+), natVal)-import GHC.TypeLits.Extra (Max)+import GHC.TypeError+ ( Assert+ , ErrorMessage (ShowType, Text, (:<>:))+ )+import GHC.TypeLits+ ( KnownNat+ , Nat+ , natVal+ , type (+)+ , type (-)+ , type (<=?)+ , type (^)+ )+import GHC.TypeLits.Extra (CLog, Max) import Data.Ix (Ix(..)) import Language.Haskell.TH (appT, conT, litT, numTyLit, sigE) import Language.Haskell.TH.Syntax (Lift(..))@@ -118,7 +135,15 @@ import Clash.Class.BitPack.BitReduction (reduceAnd, reduceOr) import Clash.Promoted.Nat (natToNatural) import Clash.Sized.Internal.BitVector (BitVector (BV), Bit, (++#), high, low, undefError)+import Clash.Sized.Internal.CheckedLiterals+ ( PotentiallyOutOfBounds+ , SignedBounds+ ) import qualified Clash.Sized.Internal.BitVector as BV+import CheckedLiterals.Class.Integer+ ( CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ ) import Clash.XException (ShowX (..), NFDataX (..), errorX, showsPrecXWith, rwhnfX) @@ -643,6 +668,34 @@ finiteBitSize = size# countLeadingZeros s = countLeadingZeros (pack# s) countTrailingZeros s = countTrailingZeros (pack# s)++type SignedPositiveLiteralError lit n =+ PotentiallyOutOfBounds+ ('ShowType lit)+ (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1))+ (CLog 2 (lit + 1) + 1)+ n++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 (lit + 1) + 1 <=? n))+ (SignedPositiveLiteralError lit n)+ ) =>+ CheckedPositiveIntegerLiteral lit (Signed n)++type SignedNegativeLiteralError lit n =+ PotentiallyOutOfBounds+ ('Text "-" ':<>: 'ShowType lit)+ (SignedBounds (Signed n) (2 ^ (n - 1)) ((2 ^ (n - 1)) - 1))+ (CLog 2 lit + 1)+ n++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 lit + 1 <=? n))+ (SignedNegativeLiteralError lit n)+ ) =>+ CheckedNegativeIntegerLiteral lit (Signed n) instance Resize Signed where resize = resize#
src/Clash/Sized/Internal/Unsigned.hs view
@@ -8,6 +8,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE RoleAnnotations #-}@@ -79,6 +80,8 @@ , unsigned8toWord8 , unsigned16toWord16 , unsigned32toWord32+ -- * Type-level error messages+ , UnsignedPositiveLiteralError ) where @@ -90,6 +93,7 @@ import Data.Data (Data) import Data.Default (Default (..)) import Data.Proxy (Proxy (..))+import Data.Type.Bool (If) import Text.Read (Read (..), ReadPrec) import Text.Printf (PrintfArg (..), printf) import GHC.Exts (wordToWord8#, wordToWord16#, wordToWord32#)@@ -100,9 +104,20 @@ import GHC.Num.Natural (Natural (..), naturalShiftL, naturalShiftR, naturalToWord) import GHC.Natural (naturalToInteger)-import GHC.TypeLits (KnownNat, Nat, type (+))+import GHC.TypeError+ ( Assert+ , ErrorMessage (ShowType)+ )+import GHC.TypeLits+ ( KnownNat+ , Nat+ , type (+)+ , type (-)+ , type (<=?)+ , type (^)+ ) import GHC.TypeNats (natVal)-import GHC.TypeLits.Extra (Max)+import GHC.TypeLits.Extra (CLog, Max) import GHC.Word (Word (..), Word8 (..), Word16 (..), Word32 (..)) import Data.Ix (Ix(..)) import Language.Haskell.TH (appT, conT, litT, numTyLit, sigE)@@ -123,8 +138,17 @@ import Clash.Class.BitPack.BitReduction (reduceOr) import Clash.Promoted.Nat (natToNum, natToNatural) import Clash.Sized.Internal.BitVector (BitVector (BV), Bit, high, low, undefError)+import Clash.Sized.Internal.CheckedLiterals+ ( PotentiallyOutOfBounds+ , UnsignedBounds+ ) import qualified Clash.Sized.Internal.BitVector as BV import Clash.Sized.Internal.Mod+import CheckedLiterals.Class.Integer+ ( NegativeUnsignedError+ , CheckedNegativeIntegerLiteral+ , CheckedPositiveIntegerLiteral+ ) import Clash.XException (ShowX (..), NFDataX (..), errorX, showsPrecXWith, rwhnfX) @@ -544,6 +568,24 @@ finiteBitSize = size# countLeadingZeros u = countLeadingZeros (pack# u) countTrailingZeros u = countTrailingZeros (pack# u)++type UnsignedPositiveLiteralError lit n =+ PotentiallyOutOfBounds+ ('ShowType lit)+ (UnsignedBounds (Unsigned n) ((2 ^ n) - 1))+ (CLog 2 (lit + 1))+ n++instance+ ( Assert+ (If (lit <=? 0) (lit <=? 0) (CLog 2 (lit + 1) <=? n))+ (UnsignedPositiveLiteralError lit n)+ ) =>+ CheckedPositiveIntegerLiteral lit (Unsigned n)++instance+ (NegativeUnsignedError lit (Unsigned n) ((2 ^ n) - 1)) =>+ CheckedNegativeIntegerLiteral lit (Unsigned n) instance Resize Unsigned where resize = resize#
src/Clash/Sized/Signed.hs view
@@ -8,6 +8,9 @@ module Clash.Sized.Signed ( Signed+ -- * Type-level error messages+ , SignedPositiveLiteralError+ , SignedNegativeLiteralError ) where
src/Clash/Sized/Unsigned.hs view
@@ -7,7 +7,10 @@ {-# LANGUAGE Trustworthy #-} module Clash.Sized.Unsigned- (Unsigned)+ ( Unsigned+ -- * Type-level error messages+ , UnsignedPositiveLiteralError+ ) where import Clash.Sized.Internal.Unsigned
+ tests/Clash/Tests/CheckedLiterals.hs view
@@ -0,0 +1,28 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++module Clash.Tests.CheckedLiterals (tests) where++import Test.Tasty (TestTree, testGroup)++import qualified Clash.Tests.CheckedLiterals.BitVector+import qualified Clash.Tests.CheckedLiterals.Fixed+import qualified Clash.Tests.CheckedLiterals.Index+import qualified Clash.Tests.CheckedLiterals.Signals+import qualified Clash.Tests.CheckedLiterals.Signed+import qualified Clash.Tests.CheckedLiterals.Unsigned+import qualified Clash.Tests.CheckedLiterals.Wrappers++tests :: TestTree+tests = testGroup "CheckedLiterals"+ [ Clash.Tests.CheckedLiterals.BitVector.tests+ , Clash.Tests.CheckedLiterals.Unsigned.tests+ , Clash.Tests.CheckedLiterals.Signed.tests+ , Clash.Tests.CheckedLiterals.Index.tests+ , Clash.Tests.CheckedLiterals.Fixed.tests+ , Clash.Tests.CheckedLiterals.Wrappers.tests+ , Clash.Tests.CheckedLiterals.Signals.tests+ ]
+ tests/Clash/Tests/CheckedLiterals/BitVector.hs view
@@ -0,0 +1,54 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++module Clash.Tests.CheckedLiterals.BitVector (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++bvMod :: String+bvMod = "Clash.Sized.BitVector"++bitTests :: TestTree+bitTests = testGroup "Bit" $ toTestCases+ [ (bvMod, "Bit", "0", [])+ , (bvMod, "Bit", "1", [])+ , (bvMod, "Bit", "-1", ["Literal -1 is out of bounds.", "Bit has bounds: [0 .. 1]."])+ , (bvMod, "Bit", "2", ["Literal 2 is out of bounds.", "Bit has bounds: [0 .. 1]."])+ ]++bitVectorTests :: TestTree+bitVectorTests = testGroup "BitVector" $ toTestCases+ [ (bvMod, "BitVector 0", "0", [])+ , (bvMod, "BitVector 0", "-1", ["Literal -1 is out of bounds.", "BitVector 0 has bounds: [0 .. 0]."])+ , (bvMod, "BitVector 0", "1", ["Literal 1 is (potentially) out of bounds.", "BitVector 0 has bounds: [0 .. 0]."])+ , (bvMod, "BitVector 1", "0", [])+ , (bvMod, "BitVector 1", "-1", ["Literal -1 is out of bounds.", "BitVector 1 has bounds: [0 .. 1]."])+ , (bvMod, "BitVector 1", "1", [])+ , (bvMod, "BitVector 1", "2", ["Literal 2 is (potentially) out of bounds.", "BitVector 1 has bounds: [0 .. 1]."])+ , (bvMod, "BitVector 2", "0", [])+ , (bvMod, "BitVector 2", "-1", ["Literal -1 is out of bounds.", "BitVector 2 has bounds: [0 .. 3]."])+ , (bvMod, "BitVector 2", "1", [])+ , (bvMod, "BitVector 2", "2", [])+ , (bvMod, "BitVector 2", "3", [])+ , (bvMod, "BitVector 2", "4", ["Literal 4 is (potentially) out of bounds.", "BitVector 2 has bounds: [0 .. 3]."])+ , (bvMod, "(KnownNat n) => BitVector n", "0", [])+ , (bvMod, "(KnownNat n) => BitVector n", "1", ["Literal 1 is (potentially) out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1]", "Possible fix: add a constraint: 1 <= n."])+ , (bvMod, "(KnownNat n) => BitVector n", "-1", ["Literal -1 is out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1]."])+ , (bvMod, "(KnownNat n, 1 <= n) => BitVector n", "0", [])+ , (bvMod, "(KnownNat n, 1 <= n) => BitVector n", "1", [])+ , (bvMod, "(KnownNat n, 1 <= n) => BitVector n", "-1", ["Literal -1 is out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1]."])+ , (bvMod, "(KnownNat n, 2 <= n) => BitVector n", "0", [])+ , (bvMod, "(KnownNat n, 2 <= n) => BitVector n", "1", [])+ , (bvMod, "(KnownNat n, 2 <= n) => BitVector n", "-1", ["Literal -1 is out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1]."])+ , (bvMod, "(KnownNat n, 7 <= n) => BitVector n", "255", ["Literal 255 is (potentially) out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1].", "Possible fix: add a constraint: 8 <= n."])+ , (bvMod, "(KnownNat n, 8 <= n) => BitVector n", "256", ["Literal 256 is (potentially) out of bounds.", "BitVector n has bounds: [0 .. (2 ^ n) - 1].", "Possible fix: add a constraint: 9 <= n."])+ ]++tests :: TestTree+tests = testGroup "BitVector" [bitTests, bitVectorTests]
+ tests/Clash/Tests/CheckedLiterals/Common.hs view
@@ -0,0 +1,46 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++{-# LANGUAGE QuasiQuotes #-}++module Clash.Tests.CheckedLiterals.Common where++import Data.List (intercalate)+import Data.String.Interpolate (__i)+import Test.Tasty (TestTree)+import Test.Tasty.AssertGhc (Expected (..), testCaseGhc)++-- | First tuple element may list several modules separated by @", "@; each one+-- gets its own @import@ line in the generated snippet. This lets a test case+-- reference types that live in different modules (e.g. a @Clash.Num.*@ wrapper+-- around a @Clash.Sized.*@ type).+toTestCases :: [(String, String, String, [String])] -> [TestTree]+toTestCases = map toTestCase++toTestCase :: (String, String, String, [String]) -> TestTree+toTestCase (moduleNames, typeName, literal, expectedErrors) =+ testCaseGhc+ ((if null expectedErrors then "OK , " else "NOK, ") ++ typeName ++ ", " ++ literal)+ [__i|+ import Prelude+ #{imports}+ import GHC.TypeNats+ test :: #{typeName}+ test = #{literal}+ |]+ ( if null expectedErrors+ then ExpectSuccess+ else ExpectFailure expectedErrors+ )+ where+ imports = intercalate "\n" ["import " ++ m | m <- splitOnCommaSpace moduleNames]++ splitOnCommaSpace :: String -> [String]+ splitOnCommaSpace s = case break (== ',') s of+ (x, "") -> [x]+ (x, ',':' ':r) -> x : splitOnCommaSpace r+ (x, ',':r) -> x : splitOnCommaSpace r+ (x, _) -> [x]
+ tests/Clash/Tests/CheckedLiterals/Fixed.hs view
@@ -0,0 +1,143 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++module Clash.Tests.CheckedLiterals.Fixed (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++fMod :: String+fMod = "Clash.Sized.Fixed"++integerTests :: TestTree+integerTests = testGroup "Integer" $ toTestCases+ [ (fMod, "(KnownNat f) => UFixed 0 f", "0", [])+ , (fMod, "(KnownNat f) => UFixed 0 f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 0 f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s)."])+ , (fMod, "(KnownNat f) => UFixed 1 f", "0", [])+ , (fMod, "(KnownNat f) => UFixed 1 f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 1 f", "1", [])+ , (fMod, "(KnownNat f) => UFixed 1 f", "2", ["Literal 2 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s)."])+ , (fMod, "(KnownNat f) => UFixed 2 f", "0", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 2 f", "1", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "2", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "3", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "4", ["Literal 4 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s)."])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s).", "Possible fix: add a constraint: 1 <= n."])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "1", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "1", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "-1", ["Literal -1 is out of bounds, because UFixed cannot represent negative numbers."])++ , (fMod, "(KnownNat f) => SFixed 0 f", "0", [])+ , (fMod, "(KnownNat f) => SFixed 0 f", "-1", ["Literal -1 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 0 f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 1 f", "0", [])+ , (fMod, "(KnownNat f) => SFixed 1 f", "-1", [])+ , (fMod, "(KnownNat f) => SFixed 1 f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 1 f", "2", ["Literal 2 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "0", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-1", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-2", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-3", ["Literal -3 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "1", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "2", ["Literal 2 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "4", ["Literal 4 is (potentially) out of bounds.", "Note: integer part needs at least 4 bit(s), including sign bit."])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit.", "Possible fix: add a constraint: 2 <= n."])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "-1", ["Literal -1 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= n."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "1", ["Literal 1 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit.", "Possible fix: add a constraint: 2 <= n."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "-1", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "1", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "-1", [])+ ]++rationalTests :: TestTree+rationalTests = testGroup "Rational" $ toTestCases+ [ (fMod, "(KnownNat f) => UFixed 0 f", "0.0", [])+ , (fMod, "(KnownNat f) => UFixed 0 f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 0 f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s)."])+ , (fMod, "(KnownNat f) => UFixed 1 f", "0.0", [])+ , (fMod, "(KnownNat f) => UFixed 1 f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 1 f", "1.0", [])+ , (fMod, "(KnownNat f) => UFixed 1 f", "2.0", ["Literal 2.0 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s)."])+ , (fMod, "(KnownNat f) => UFixed 2 f", "0.0", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f) => UFixed 2 f", "1.0", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "2.0", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "3.0", [])+ , (fMod, "(KnownNat f) => UFixed 2 f", "4.0", ["Literal 4.0 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s)."])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s).", "Possible fix: add a constraint: 1 <= n."])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "1.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => UFixed n f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "1.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => UFixed n f", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])++ , (fMod, "(KnownNat f) => SFixed 0 f", "0.0", [])+ , (fMod, "(KnownNat f) => SFixed 0 f", "-1.0", ["Literal -1.0 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 0 f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 1 f", "0.0", [])+ , (fMod, "(KnownNat f) => SFixed 1 f", "-1.0", [])+ , (fMod, "(KnownNat f) => SFixed 1 f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 1 f", "2.0", ["Literal 2.0 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "0.0", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-1.0", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-2.0", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "-3.0", ["Literal -3.0 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "1.0", [])+ , (fMod, "(KnownNat f) => SFixed 2 f", "2.0", ["Literal 2.0 is (potentially) out of bounds.", "Note: integer part needs at least 3 bit(s), including sign bit."])+ , (fMod, "(KnownNat f) => SFixed 2 f", "4.0", ["Literal 4.0 is (potentially) out of bounds.", "Note: integer part needs at least 4 bit(s), including sign bit."])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit.", "Possible fix: add a constraint: 2 <= n."])+ , (fMod, "(KnownNat f, KnownNat n) => SFixed n f", "-1.0", ["Literal -1.0 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= n."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "1.0", ["Literal 1.0 is (potentially) out of bounds.", "Note: integer part needs at least 2 bit(s), including sign bit.", "Possible fix: add a constraint: 2 <= n."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n) => SFixed n f", "-1.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "0.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "1.0", [])+ , (fMod, "(KnownNat f, KnownNat n, 2 <= n) => SFixed n f", "-1.0", [])++ , (fMod, "UFixed 0 0", "0.5", ["Literal 0.5 cannot be represented exactly by Fixed", "The fractional part needs at least 1 bit(s)."])+ , (fMod, "UFixed 0 1", "0.5", [])+ , (fMod, "UFixed 0 1", "0.75", ["Literal 0.75 cannot be represented exactly by Fixed", "The fractional part needs at least 2 bit(s)."])+ , (fMod, "UFixed 0 1", "0.1", ["Literal 0.1 cannot be represented exactly by", "The reduced denominator 10 is not a power of 2."])+ , (fMod, "(KnownNat f, 1 <= f) => UFixed 0 f", "0.5", [])+ , (fMod, "(KnownNat f, 1 <= f) => UFixed 0 f", "0.75", ["Literal 0.75 cannot be represented exactly by Fixed", "The fractional part needs at least 2 bit(s).", "Possible fix: add a constraint: 2 <= f."])+ , (fMod, "(KnownNat f, 2 <= f) => UFixed 0 f", "0.75", [])+ , (fMod, "(KnownNat f, 3 <= f) => UFixed 0 f", "0.75", [])++ , (fMod, "SFixed 0 0", "0.5", ["Literal 0.5 cannot be represented exactly by Fixed", "The fractional part needs at least 1 bit(s)."])+ , (fMod, "SFixed 0 1", "0.5", ["Literal 0.5 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= 0."])+ , (fMod, "SFixed 0 1", "0.75", ["Literal 0.75 cannot be represented exactly by Fixed", "The fractional part needs at least 2 bit(s)."])+ , (fMod, "SFixed 0 1", "0.1", ["Literal 0.1 cannot be represented exactly by", "The reduced denominator 10 is not a power of 2."])+ , (fMod, "(KnownNat f, 1 <= f) => SFixed 0 f", "0.5", ["Literal 0.5 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= 0."])+ , (fMod, "(KnownNat f, 1 <= f) => SFixed 0 f", "0.75", ["Literal 0.75 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= 0."])+ , (fMod, "(KnownNat f, 2 <= f) => SFixed 0 f", "0.75", ["Literal 0.75 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= 0."])+ , (fMod, "(KnownNat f, 3 <= f) => SFixed 0 f", "0.75", ["Literal 0.75 is (potentially) out of bounds.", "Note: integer part needs at least 1 bit(s), including sign bit.", "Possible fix: add a constraint: 1 <= 0."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n, 1 <= f) => SFixed n f", "0.5", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n, 1 <= f) => SFixed n f", "0.75", ["Literal 0.75 cannot be represented exactly by Fixed", "The fractional part needs at least 2 bit(s).", "Possible fix: add a constraint: 2 <= f."])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n, 2 <= f) => SFixed n f", "0.75", [])+ , (fMod, "(KnownNat f, KnownNat n, 1 <= n, 3 <= f) => SFixed n f", "0.75", [])++ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "255.0", ["Literal 255.0 is (potentially) out of bounds.", "Note: integer part needs at least 8 bit(s).", "Possible fix: add a constraint: 8 <= n."])+ , (fMod, "(KnownNat f, KnownNat n) => UFixed n f", "256.0", ["Literal 256.0 is (potentially) out of bounds.", "Note: integer part needs at least 9 bit(s).", "Possible fix: add a constraint: 9 <= n."])+ ]++tests :: TestTree+tests = testGroup "Fixed" [integerTests, rationalTests]
+ tests/Clash/Tests/CheckedLiterals/Index.hs view
@@ -0,0 +1,44 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>++The type argument of 'Index' is the exclusive upper bound, not a bit width,+so @Index 4@ has bounds @[0 .. 3]@ (the same range as @Unsigned 2@). The+polymorphic bounds message therefore reads @Index n has bounds: [0 .. n - 1]@+rather than @[0 .. (2 ^ n) - 1]@.+-}++module Clash.Tests.CheckedLiterals.Index (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++iMod :: String+iMod = "Clash.Sized.Index"++tests :: TestTree+tests = testGroup "Index" $ toTestCases+ [ (iMod, "Index 1", "0", [])+ , (iMod, "Index 1", "-1", ["Literal -1 is out of bounds.", "Index 1 has bounds: [0 .. 0]."])+ , (iMod, "Index 1", "1", ["Literal 1 is (potentially) out of bounds.", "Index 1 has bounds: [0 .. 0]."])+ , (iMod, "Index 2", "0", [])+ , (iMod, "Index 2", "-1", ["Literal -1 is out of bounds.", "Index 2 has bounds: [0 .. 1]."])+ , (iMod, "Index 2", "1", [])+ , (iMod, "Index 2", "2", ["Literal 2 is (potentially) out of bounds.", "Index 2 has bounds: [0 .. 1]."])+ , (iMod, "Index 4", "0", [])+ , (iMod, "Index 4", "-1", ["Literal -1 is out of bounds.", "Index 4 has bounds: [0 .. 3]."])+ , (iMod, "Index 4", "1", [])+ , (iMod, "Index 4", "3", [])+ , (iMod, "Index 4", "4", ["Literal 4 is (potentially) out of bounds.", "Index 4 has bounds: [0 .. 3]."])+ , (iMod, "(KnownNat n) => Index n", "0", ["Literal 0 is (potentially) out of bounds.", "Index n has bounds: [0 .. n - 1].", "Possible fix: add a constraint: 1 <= n."])+ , (iMod, "(KnownNat n) => Index n", "1", ["Literal 1 is (potentially) out of bounds.", "Index n has bounds: [0 .. n - 1]", "Possible fix: add a constraint: 2 <= n."])+ , (iMod, "(KnownNat n) => Index n", "-1", ["Literal -1 is out of bounds.", "Index n has bounds: [0 .. n - 1]."])+ , (iMod, "(KnownNat n, 1 <= n) => Index n", "0", [])+ , (iMod, "(KnownNat n, 2 <= n) => Index n", "1", [])+ , (iMod, "(KnownNat n, 1 <= n) => Index n", "-1", ["Literal -1 is out of bounds.", "Index n has bounds: [0 .. n - 1]."])+ , (iMod, "(KnownNat n, 3 <= n) => Index n", "2", [])+ , (iMod, "(KnownNat n, 3 <= n) => Index n", "3", ["Literal 3 is (potentially) out of bounds.", "Index n has bounds: [0 .. n - 1].", "Possible fix: add a constraint: 4 <= n."])+ ]
+ tests/Clash/Tests/CheckedLiterals/Signals.hs view
@@ -0,0 +1,42 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>++Smoke tests for the passthrough @CheckedLiteral@ instances on 'Signal' and+'DSignal': they forward the check to the signal's element type.++The @toTestCases@ helper only injects one module import, so we rely on+'System' being re-exported from 'Clash.Signal' and 'Clash.Signal.Delayed'.+-}++module Clash.Tests.CheckedLiterals.Signals (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++pMod :: String+pMod = "Clash.Prelude"++signalTests :: TestTree+signalTests = testGroup "Signal" $ toTestCases+ [ (pMod, "Signal System (Unsigned 2)", "3", [])+ , (pMod, "Signal System (Unsigned 2)", "4", ["Literal 4 is (potentially) out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])+ , (pMod, "Signal System (Signed 2)", "-2", [])+ , (pMod, "Signal System (Signed 2)", "2", ["Signed 2 has bounds: [-2 .. 1]"])+ , (pMod, "Signal System (UFixed 1 2)", "0.75", [])+ , (pMod, "Signal System (UFixed 1 2)", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ ]++dsignalTests :: TestTree+dsignalTests = testGroup "DSignal" $ toTestCases+ [ (pMod, "DSignal System 0 (Unsigned 2)", "3", [])+ , (pMod, "DSignal System 0 (Unsigned 2)", "4", ["Literal 4 is (potentially) out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])+ , (pMod, "DSignal System 0 (Signed 2)", "-2", [])+ , (pMod, "DSignal System 0 (Signed 2)", "2", ["Signed 2 has bounds: [-2 .. 1]"])+ ]++tests :: TestTree+tests = testGroup "Signals" [signalTests, dsignalTests]
+ tests/Clash/Tests/CheckedLiterals/Signed.hs view
@@ -0,0 +1,43 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++module Clash.Tests.CheckedLiterals.Signed (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++sMod :: String+sMod = "Clash.Sized.Signed"++tests :: TestTree+tests = testGroup "Signed" $ toTestCases+ [ (sMod, "Signed 0", "0", [])+ , (sMod, "Signed 0", "-1", ["Literal -1 is (potentially) out of bounds."])+ , (sMod, "Signed 0", "1", ["Literal 1 is (potentially) out of bounds."])+ , (sMod, "Signed 1", "0", [])+ , (sMod, "Signed 1", "-1", [])+ , (sMod, "Signed 1", "1", ["Literal 1 is (potentially) out of bounds.", "Signed 1 has bounds: [-1 .. 0]"])+ , (sMod, "Signed 2", "0", [])+ , (sMod, "Signed 2", "-1", [])+ , (sMod, "Signed 2", "-2", [])+ , (sMod, "Signed 2", "-3", ["Literal -3 is (potentially) out of bounds.", "Signed 2 has bounds: [-2 .. 1]"])+ , (sMod, "Signed 2", "1", [])+ , (sMod, "Signed 2", "2", ["Signed 2 has bounds: [-2 .. 1]"])+ , (sMod, "(KnownNat n) => Signed n", "0", [])+ , (sMod, "(KnownNat n) => Signed n", "1", ["Signed n has bounds: [-2 ^ (n - 1) .. (2 ^ (n - 1)) - 1]", "Possible fix: add a constraint: 2 <= n."])+ , (sMod, "(KnownNat n) => Signed n", "-1", ["Literal -1 is (potentially) out of bounds.", "Signed n has bounds: [-2 ^ (n - 1) .. (2 ^ (n - 1)) - 1]", "Possible fix: add a constraint: 1 <= n."])+ , (sMod, "(KnownNat n, 1 <= n) => Signed n", "0", [])+ , (sMod, "(KnownNat n, 1 <= n) => Signed n", "1", ["Signed n has bounds: [-2 ^ (n - 1) .. (2 ^ (n - 1)) - 1]", "Possible fix: add a constraint: 2 <= n."])+ , (sMod, "(KnownNat n, 1 <= n) => Signed n", "-1", [])+ , (sMod, "(KnownNat n, 2 <= n) => Signed n", "0", [])+ , (sMod, "(KnownNat n, 2 <= n) => Signed n", "1", [])+ , (sMod, "(KnownNat n, 2 <= n) => Signed n", "-1", [])+ , (sMod, "(KnownNat n, 3 <= n) => Signed n", "0", [])+ , (sMod, "(KnownNat n, 3 <= n) => Signed n", "1", [])+ , (sMod, "(KnownNat n, 3 <= n) => Signed n", "-1", [])+ ]
+ tests/Clash/Tests/CheckedLiterals/Unsigned.hs view
@@ -0,0 +1,43 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>+-}++module Clash.Tests.CheckedLiterals.Unsigned (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++uMod :: String+uMod = "Clash.Sized.Unsigned"++tests :: TestTree+tests = testGroup "Unsigned" $ toTestCases+ [ (uMod, "Unsigned 0", "0", [])+ , (uMod, "Unsigned 0", "-1", ["Literal -1 is out of bounds.", "Unsigned 0 has bounds: [0 .. 0]."])+ , (uMod, "Unsigned 0", "1", ["Literal 1 is (potentially) out of bounds.", "Unsigned 0 has bounds: [0 .. 0]."])+ , (uMod, "Unsigned 1", "0", [])+ , (uMod, "Unsigned 1", "-1", ["Literal -1 is out of bounds.", "Unsigned 1 has bounds: [0 .. 1]."])+ , (uMod, "Unsigned 1", "1", [])+ , (uMod, "Unsigned 1", "2", ["Literal 2 is (potentially) out of bounds.", "Unsigned 1 has bounds: [0 .. 1]."])+ , (uMod, "Unsigned 2", "0", [])+ , (uMod, "Unsigned 2", "-1", ["Literal -1 is out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])+ , (uMod, "Unsigned 2", "1", [])+ , (uMod, "Unsigned 2", "2", [])+ , (uMod, "Unsigned 2", "3", [])+ , (uMod, "Unsigned 2", "4", ["Literal 4 is (potentially) out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])+ , (uMod, "(KnownNat n) => Unsigned n", "0", [])+ , (uMod, "(KnownNat n) => Unsigned n", "1", ["Literal 1 is (potentially) out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1]", "Possible fix: add a constraint: 1 <= n."])+ , (uMod, "(KnownNat n) => Unsigned n", "-1", ["Literal -1 is out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1]."])+ , (uMod, "(KnownNat n, 1 <= n) => Unsigned n", "0", [])+ , (uMod, "(KnownNat n, 1 <= n) => Unsigned n", "1", [])+ , (uMod, "(KnownNat n, 1 <= n) => Unsigned n", "-1", ["Literal -1 is out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1]."])+ , (uMod, "(KnownNat n, 2 <= n) => Unsigned n", "0", [])+ , (uMod, "(KnownNat n, 2 <= n) => Unsigned n", "1", [])+ , (uMod, "(KnownNat n, 2 <= n) => Unsigned n", "-1", ["Literal -1 is out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1]."])+ , (uMod, "(KnownNat n, 7 <= n) => Unsigned n", "255", ["Literal 255 is (potentially) out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1].", "Possible fix: add a constraint: 8 <= n."])+ , (uMod, "(KnownNat n, 8 <= n) => Unsigned n", "256", ["Literal 256 is (potentially) out of bounds.", "Unsigned n has bounds: [0 .. (2 ^ n) - 1].", "Possible fix: add a constraint: 9 <= n."])+ ]
+ tests/Clash/Tests/CheckedLiterals/Wrappers.hs view
@@ -0,0 +1,43 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>++Smoke tests for the passthrough @CheckedLiteral@ instances on the numeric+wrapper newtypes: they should forward the check to the underlying type —+good literals type-check, bad ones surface the underlying type's error.+-}++module Clash.Tests.CheckedLiterals.Wrappers (tests) where++import Prelude++import Test.Tasty (TestTree, testGroup)+import Clash.Tests.CheckedLiterals.Common (toTestCases)++wrapU, satS, ovU, zerS, errUF :: String+wrapU = "Clash.Num.Wrapping, Clash.Sized.Unsigned"+satS = "Clash.Num.Saturating, Clash.Sized.Signed"+ovU = "Clash.Num.Overflowing, Clash.Sized.Unsigned"+zerS = "Clash.Num.Zeroing, Clash.Sized.Signed"+errUF = "Clash.Num.Erroring, Clash.Sized.Fixed"++tests :: TestTree+tests = testGroup "Wrappers" $ toTestCases+ [ (wrapU, "Wrapping (Unsigned 2)", "3", [])+ , (wrapU, "Wrapping (Unsigned 2)", "4", ["Literal 4 is (potentially) out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])+ , (wrapU, "Wrapping (Unsigned 2)", "-1", ["Literal -1 is out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])++ , (satS, "Saturating (Signed 2)", "-2", [])+ , (satS, "Saturating (Signed 2)", "2", ["Signed 2 has bounds: [-2 .. 1]"])++ , (ovU, "Overflowing (Unsigned 2)", "3", [])+ , (ovU, "Overflowing (Unsigned 2)", "4", ["Literal 4 is (potentially) out of bounds.", "Unsigned 2 has bounds: [0 .. 3]."])++ , (zerS, "Zeroing (Signed 2)", "-1", [])+ , (zerS, "Zeroing (Signed 2)", "2", ["Signed 2 has bounds: [-2 .. 1]"])++ , (errUF, "Erroring (UFixed 1 2)", "0.75", [])+ , (errUF, "Erroring (UFixed 1 2)", "-1.0", ["Literal -1.0 is out of bounds, because UFixed cannot represent negative numbers."])+ , (errUF, "Erroring (UFixed 1 2)", "0.1", ["Literal 0.1 cannot be represented exactly by", "The reduced denominator 10 is not a power of 2."])+ ]
tests/Clash/Tests/Laws/SaturatingNum.hs view
@@ -21,6 +21,7 @@ import Test.Tasty.HUnit.Extra import Clash.Class.Num+import Clash.Num.Overflowing (Overflowing, toOverflowing) import Clash.Sized.Index (Index) import Clash.Sized.Signed (Signed) import Clash.Sized.Fixed (SFixed, UFixed)@@ -151,12 +152,21 @@ genIndex :: forall n. KnownNat n => Gen (Index n) genIndex = genBoundedIntegral +genOIndex :: forall n. KnownNat n => Gen (Overflowing (Index n))+genOIndex = toOverflowing <$> genIndex+ genUnsigned :: forall n. KnownNat n => Gen (Unsigned n) genUnsigned = genBoundedIntegral +genOUnsigned :: forall n. KnownNat n => Gen (Overflowing (Unsigned n))+genOUnsigned = toOverflowing <$> genUnsigned+ genSigned :: forall n. KnownNat n => Gen (Signed n) genSigned = genBoundedIntegral +genOSigned :: forall n. KnownNat n => Gen (Overflowing (Signed n))+genOSigned = toOverflowing <$> genSigned+ -- | Generates a bounded fractional with a bias towards extreme values: -- -- 5%: minBound@@ -179,9 +189,15 @@ genSFixed :: forall a b. (KnownNat a, KnownNat b) => Gen (SFixed a b) genSFixed = genBoundedFractional +genOSFixed :: forall a b. (KnownNat a, KnownNat b) => Gen (Overflowing (SFixed a b))+genOSFixed = toOverflowing <$> genSFixed+ genUFixed :: forall a b. (KnownNat a, KnownNat b) => Gen (UFixed a b) genUFixed = genBoundedFractional +genOUFixed :: forall a b. (KnownNat a, KnownNat b) => Gen (Overflowing (UFixed a b))+genOUFixed = toOverflowing <$> genUFixed+ tests :: TestTree tests = testGroup "SaturatingNum" [ testSaturationLaws True "Index 1" (genIndex @1)@@ -225,4 +241,20 @@ , testSaturationLaws False "UFixed 7 7" (genUFixed @7 @7) , testSaturationLaws False "UFixed 121 121" (genUFixed @121 @121) , testSaturationLaws False "UFixed 128 128" (genUFixed @128 @128)++ , testSaturationLaws True "Overflowing (Index 1)" (genOIndex @1)+ , testSaturationLaws True "Overflowing (Index 10)" (genOIndex @10)+ , testSaturationLaws True "Overflowing (Signed 0)" (genOSigned @0)+ , testSaturationLaws True "Overflowing (Signed 8)" (genOSigned @8)+ , testSaturationLaws True "Overflowing (Unsigned 0)" (genOUnsigned @0)+ , testSaturationLaws True "Overflowing (Unsigned 8)" (genOUnsigned @8)+ , testSaturationLaws False "Overflowing (UFixed 7 7)" (genOUFixed @7 @7)+ , testSaturationLaws False "Overflowing (SFixed 0 0)" (genOSFixed @0 @0)+ , testSaturationLaws False "Overflowing (SFixed 0 1)" (genOSFixed @0 @1)+ , testSaturationLaws False "Overflowing (SFixed 1 0)" (genOSFixed @1 @0)+ , testSaturationLaws False "Overflowing (SFixed 7 7)" (genOSFixed @7 @7)+ , testSaturationLaws False "Overflowing (UFixed 0 0)" (genOUFixed @0 @0)+ , testSaturationLaws False "Overflowing (UFixed 0 1)" (genOUFixed @0 @1)+ , testSaturationLaws False "Overflowing (UFixed 1 0)" (genOUFixed @1 @0)+ , testSaturationLaws False "Overflowing (UFixed 7 7)" (genOUFixed @7 @7) ]
tests/Clash/Tests/TopEntityGeneration.hs view
@@ -73,7 +73,15 @@ , someOtherField :: "c" ::: Signal System ("wobble" ::: Int) } +newtype N a = N a +data NewtypedRecord =+ NewtypedRecord+ { nrA :: "a" ::: Bool+ , nrB :: "b" ::: Bool+ }++ topEntity1 :: "in1" ::: Signal System Int -> "in2" ::: Signal System Bool -> "out" ::: Signal System Int@@ -261,6 +269,17 @@ ] (PortName "out") +-- See https://github.com/clash-lang/clash-compiler/issues/3066+topEntity11 :: "o" ::: N NewtypedRecord+topEntity11 = undefined+makeTopEntity 'topEntity11++expectedTopEntity11 :: TopEntity+expectedTopEntity11 =+ Synthesize "topEntity11"+ []+ (PortProduct "o" [PortName "a", PortName "b"])+ topEntityFailure1 :: "int" ::: Signal System Int -> "tuple" ::: ("tup1" ::: Signal System (BitVector 7), "tup2" ::: Signal System (BitVector 9))@@ -342,6 +361,9 @@ , testCase "topEntity10" $ $(unTypeQ $ maybeBuildTopEntity Nothing 'topEntity10) @?= Just expectedTopEntity10+ , testCase "topEntity11" $+ $(unTypeQ $ maybeBuildTopEntity Nothing 'topEntity11)+ @?= Just expectedTopEntity11 ] , testGroup "Expected failures" [ testCase "topEntityFailure1" $
+ tests/Test/Tasty/AssertGhc.hs view
@@ -0,0 +1,127 @@+{-|+Copyright : (C) 2026, QBayLogic B.V.+License : BSD2 (see the file LICENSE)+Maintainer : QBayLogic B.V. <devops@qbaylogic.com>++Compile-time assertion helpers for @checked-literals@ tests: spawns a+subprocess GHC on a generated module and checks whether it succeeds or+fails with the expected error substrings.++Ported from+<https://github.com/clash-lang/checked-literals/blob/main/tests/Test/Tasty/AssertGhc.hs>.+-}++{-# LANGUAGE CPP #-}++module Test.Tasty.AssertGhc where++import Prelude++import Data.List (isInfixOf)+import Data.Maybe (fromMaybe)+import System.Environment (lookupEnv)+import System.Exit+import System.IO+import System.IO.Temp+import System.Process+import Test.Tasty (TestTree, askOption)+import Test.Tasty.HUnit+import Test.Tasty.Options+import Text.Read (readMaybe)++data Expected = ExpectFailure [String] | ExpectSuccess++-- | Option to enable debug output of GHC error messages+newtype DebugGhc = DebugGhc Bool+ deriving (Show, Read)++instance IsOption DebugGhc where+ defaultValue = DebugGhc False+ parseValue = fmap DebugGhc . readMaybe+ optionName = return "debug-ghc"+ optionHelp = return "Print full GHC output for error test cases"+ optionCLParser = flagCLParser Nothing (DebugGhc True)++testCaseGhc :: String -> String -> Expected -> TestTree+testCaseGhc name source expected =+ askOption $ \(DebugGhc debugGhc) ->+ testCaseInfo name $ do+ debugOutput <- assertGhc source expected+ if debugGhc then return debugOutput else return ""++{- | Assert that a Haskell code snippet fails to compile with expected error messages+Returns the GHC output for display in test results if debug flag is set.++The subprocess GHC picks up @clash-prelude@ and @checked-literals@ via the+@.ghc.environment.*@ file that cabal drops next to the test binary. This means+the test binary must be run from (or below) the project root where cabal+generates the environment file; @cabal run clash-prelude:unittests@ satisfies+that.+-}+assertGhc :: String -> Expected -> IO String+assertGhc source expected = do+ -- XXX: This will pick the wrong GHC if the HC environment variable (as seen on CI)+ -- isn't set and the test suite is compiled with a GHC compiler other than the+ -- system's default.+ hc <- fromMaybe "ghc" <$> lookupEnv "HC"+ withSystemTempFile "ShouldError.hs" $ \tempFile tempHandle -> do+ -- Write source with proper Main module structure+ hPutStr tempHandle "module Main where\n"+ hPutStr tempHandle source+ hPutStr tempHandle "\nmain :: IO ()\nmain = return ()\n"+ hClose tempHandle+ (exitCode, _, stderrOutput) <-+ readProcessWithExitCode+ hc+ [ "-XCPP"+ , "-XDataKinds"+ , "-XTypeOperators"+ , "-XTypeApplications"+ , "-XTypeFamilies"+ , "-XFlexibleContexts"+ , "-XUndecidableInstances"+ , "-XNoStarIsType"+ , "-XViewPatterns"+ , "-XNoImplicitPrelude"+ , "-fno-code"+ , "-package", "clash-prelude"+ , "-package", "checked-literals"+ , "-fplugin=GHC.TypeLits.KnownNat.Solver"+ , "-fplugin=GHC.TypeLits.Normalise"+ , "-fplugin=GHC.TypeLits.Extra.Solver"+ , "-fplugin=CheckedLiterals"+ , tempFile+ ]+ ""+ case (exitCode, expected) of+ (ExitSuccess, ExpectSuccess) ->+ return ""+ (ExitSuccess, ExpectFailure _) ->+ assertFailure "Expected compilation to fail but it succeeded" >> return ""+ (ExitFailure _, ExpectSuccess) ->+ assertFailure ("Expected compilation to succeed but it failed with error:\n" ++ stderrOutput)+ >> return ""+ (ExitFailure _, ExpectFailure expectedErrors) ->+ let cleanedStderr = removeProblemChars stderrOutput+ cleanedExpected = map removeProblemChars expectedErrors+ in if all (`isInfixOf` cleanedStderr) cleanedExpected+ then return stderrOutput+ else do+ _ <-+ assertFailure $+ "Error message mismatch:\n"+ ++ "Expected substrings: "+ ++ show expectedErrors+ ++ "\n"+ ++ "Actual output:\n"+ ++ stderrOutput+ return stderrOutput++{- | Remove problematic characters that vary depending on locale+The kind and amount of quotes in GHC error messages changes depending on+whether or not our locale supports unicode.+-}+removeProblemChars :: String -> String+removeProblemChars = filter (`notElem` problemChars)+ where+ problemChars = "\x2018\x2019`'"
tests/unittests.hs view
@@ -8,6 +8,7 @@ import qualified Clash.Tests.BitVector import qualified Clash.Tests.BlockRam import qualified Clash.Tests.BlockRam.Blob+import qualified Clash.Tests.CheckedLiterals import qualified Clash.Tests.Clocks import qualified Clash.Tests.Counter import qualified Clash.Tests.DerivingDataRepr@@ -42,6 +43,7 @@ , Clash.Tests.BitVector.tests , Clash.Tests.BlockRam.Blob.tests , Clash.Tests.BlockRam.tests+ , Clash.Tests.CheckedLiterals.tests , Clash.Tests.Clocks.tests , Clash.Tests.Counter.tests , Clash.Tests.DerivingDataRepr.tests