diff --git a/changelog.d/20260921_122034_teofilcamarasu_expr_role.md b/changelog.d/20260921_122034_teofilcamarasu_expr_role.md new file mode 100644 index 00000000..708ce69c --- /dev/null +++ b/changelog.d/20260921_122034_teofilcamarasu_expr_role.md @@ -0,0 +1,3 @@ +### Fixed + +- Make `Expr` have a representational role, which disallows freely coercing the type within `Expr`. Users can still use `unsafeCastExpr` if they want this behaviour. diff --git a/rel8-internal/src/Rel8/Internal/Expr.hs b/rel8-internal/src/Rel8/Internal/Expr.hs index f309c22a..794eab4b 100644 --- a/rel8-internal/src/Rel8/Internal/Expr.hs +++ b/rel8-internal/src/Rel8/Internal/Expr.hs @@ -9,6 +9,7 @@ {-# language TypeApplications #-} {-# language TypeFamilies #-} {-# language UndecidableInstances #-} +{-# language RoleAnnotations #-} module Rel8.Internal.Expr ( Expr(..) @@ -53,6 +54,7 @@ import Data.Scientific (fromRationalRepetendLimited) -- | Typed SQL expressions. type Expr :: K.Context +type role Expr nominal newtype Expr a = Expr Opaleye.PrimExpr deriving stock Show diff --git a/rel8-internal/src/Rel8/Internal/Expr.hs-boot b/rel8-internal/src/Rel8/Internal/Expr.hs-boot index f64934eb..6891238d 100644 --- a/rel8-internal/src/Rel8/Internal/Expr.hs-boot +++ b/rel8-internal/src/Rel8/Internal/Expr.hs-boot @@ -1,5 +1,6 @@ {-# language DataKinds #-} {-# language StandaloneKindSignatures #-} +{-# language RoleAnnotations #-} module Rel8.Internal.Expr ( Expr(..) @@ -17,4 +18,5 @@ import Rel8.Internal.Schema.Kind ( Context ) type Expr :: Context +type role Expr nominal newtype Expr a = Expr Opaleye.PrimExpr