Skip to content

Commit a7cb12f

Browse files
committed
Propagate 'Codable' bounds through MoatData tyvars
1 parent 16dfdc9 commit a7cb12f

File tree

10 files changed

+96
-6
lines changed

10 files changed

+96
-6
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@Parcelize
2+
@Serializable
3+
value class LTree<A : Parcelable>(val value: List<A>) : Parcelable
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Non-empty, possibly infinite, multi-way trees; also known as *rose trees*.
3+
*
4+
* @param rootLabel label value
5+
* @param subForest zero or more child trees
6+
*/
7+
data class Tree<A : Parcelable>(
8+
val rootLabel: A,
9+
val subForest: List<Tree<A>>,
10+
) : Parcelable
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
struct LTree<A: Codable>: CaseIterable, Hashable, Codable {
2+
typealias LTreeTag = Tagged<LTree, [A]>
3+
let value: LTreeTag
4+
}

.golden/swiftGenericStructSpec/golden

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/// Non-empty, possibly infinite, multi-way trees; also known as *rose trees*.
2+
struct Tree<A: Codable>: Codable {
3+
/// label value
4+
var rootLabel: A
5+
/// zero or more child trees
6+
var subForest: [Tree<A>]
7+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
struct Data<A, B>: CaseIterable, Hashable, Codable {
1+
struct Data<A: Codable, B: Codable>: CaseIterable, Hashable, Codable {
22
var field0: A
33
var field1: B
44
}

.golden/swiftTypeVariableSpec/golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
struct Data<A>: CaseIterable, Hashable, Codable {
1+
struct Data<A: Codable>: CaseIterable, Hashable, Codable {
22
var field0: A
33
}

moat.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ test-suite spec
8383
DuplicateRecordFieldSpec
8484
EnumValueClassDocSpec
8585
EnumValueClassSpec
86+
GenericNewtypeSpec
87+
GenericStructSpec
8688
MultipleTypeVariableSpec
8789
StrictEnumsSpec
8890
StrictFieldsSpec

src/Moat/Pretty/Swift.hs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ prettySwiftDataWith indent = \case
2828
MoatEnum {..} ->
2929
prettyTypeDoc "" enumDoc []
3030
++ "enum "
31-
++ prettyMoatTypeHeader enumName enumTyVars
31+
++ prettyMoatTypeHeader enumName (addTyVarBounds enumTyVars enumProtocols)
3232
++ prettyRawValueAndProtocols enumRawValue enumProtocols
3333
++ " {"
3434
++ newlineNonEmpty enumCases
@@ -41,7 +41,7 @@ prettySwiftDataWith indent = \case
4141
MoatStruct {..} ->
4242
prettyTypeDoc "" structDoc []
4343
++ "struct "
44-
++ prettyMoatTypeHeader structName structTyVars
44+
++ prettyMoatTypeHeader structName (addTyVarBounds structTyVars structProtocols)
4545
++ prettyRawValueAndProtocols Nothing structProtocols
4646
++ " {"
4747
++ newlineNonEmpty structFields
@@ -54,13 +54,13 @@ prettySwiftDataWith indent = \case
5454
MoatAlias {..} ->
5555
prettyTypeDoc "" aliasDoc []
5656
++ "typealias "
57-
++ prettyMoatTypeHeader aliasName aliasTyVars
57+
++ prettyMoatTypeHeader aliasName (addTyVarBounds aliasTyVars [])
5858
++ " = "
5959
++ prettyMoatType aliasTyp
6060
MoatNewtype {..} ->
6161
prettyTypeDoc "" newtypeDoc []
6262
++ "struct "
63-
++ prettyMoatTypeHeader newtypeName newtypeTyVars
63+
++ prettyMoatTypeHeader newtypeName (addTyVarBounds newtypeTyVars newtypeProtocols)
6464
++ prettyRawValueAndProtocols Nothing newtypeProtocols
6565
++ " {\n"
6666
++ indents
@@ -268,3 +268,8 @@ prettyPrivateTypes indents = go
268268
onLast :: (a -> a) -> [a] -> [a]
269269
onLast _ [] = []
270270
onLast f (x : xs) = x : map f xs
271+
272+
addTyVarBounds :: [String] -> [Protocol] -> [String]
273+
addTyVarBounds tyVars protos
274+
| Codable `elem` protos = map (++ ": Codable") tyVars
275+
| otherwise = tyVars

test/GenericNewtypeSpec.hs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{-# LANGUAGE DerivingStrategies #-}
2+
3+
module GenericNewtypeSpec where
4+
5+
import Common
6+
import Data.List.NonEmpty (NonEmpty)
7+
import Moat
8+
import Test.Hspec
9+
import Test.Hspec.Golden
10+
import Prelude
11+
12+
newtype LTree a = LTree (NonEmpty a)
13+
deriving stock (Show, Eq)
14+
15+
mobileGenWith
16+
( defaultOptions
17+
{ dataAnnotations = [Parcelize, Serializable]
18+
, dataInterfaces = [Parcelable]
19+
, dataProtocols = [OtherProtocol "CaseIterable", Hashable, Codable]
20+
, dataRawValue = Just Str
21+
}
22+
)
23+
''LTree
24+
25+
spec :: Spec
26+
spec =
27+
describe "stays golden" $ do
28+
let moduleName = "GenericNewtypeSpec"
29+
it "swift" $
30+
defaultGolden ("swift" <> moduleName) (showSwift @(LTree _))
31+
it "kotlin" $
32+
defaultGolden ("kotlin" <> moduleName) (showKotlin @(LTree _))

test/GenericStructSpec.hs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{-# OPTIONS_GHC -Wno-orphans #-}
2+
3+
module GenericStructSpec where
4+
5+
import Common
6+
import Data.Tree (Tree)
7+
import Moat
8+
import Test.Hspec
9+
import Test.Hspec.Golden
10+
import Prelude
11+
12+
mobileGenWith
13+
( defaultOptions
14+
{ dataInterfaces = [Parcelable]
15+
, dataProtocols = [Codable]
16+
}
17+
)
18+
''Tree
19+
20+
spec :: Spec
21+
spec =
22+
describe "stays golden" $ do
23+
let moduleName = "GenericStructSpec"
24+
it "swift" $
25+
defaultGolden ("swift" <> moduleName) (showSwift @(Tree _))
26+
it "kotlin" $
27+
defaultGolden ("kotlin" <> moduleName) (showKotlin @(Tree _))

0 commit comments

Comments
 (0)