Skip to content

Commit

Permalink
fix: improve TypeReference supports when inside of an Union especia…
Browse files Browse the repository at this point in the history
…lly when dealing with `TypeParameters`

[converter][web]

Fix #113
  • Loading branch information
MangelMaxime committed Jul 16, 2024
1 parent a413d14 commit cc99bab
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 63 deletions.
7 changes: 6 additions & 1 deletion src/Glutinum.Converter/FsharpAST.fs
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,17 @@ type FSharpUnionCaseType =
// | Float of float
// | Int of int

type FSharpUnionCase =
type FSharpUnionCaseNamed =
{
Attributes: FSharpAttribute list
Name: string
}

[<RequireQualifiedAccess>]
type FSharpUnionCase =
| Named of FSharpUnionCaseNamed
| Typed of FSharpType

[<RequireQualifiedAccess>]
type FSharpUnionType =
| String
Expand Down
17 changes: 14 additions & 3 deletions src/Glutinum.Converter/Printer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,13 @@ and printType (fsharpType: FSharpType) =

| FSharpType.Union info ->
let cases =
info.Cases |> List.map (fun c -> c.Name) |> String.concat ", "
info.Cases
|> List.map (fun case ->
match case with
| FSharpUnionCase.Named caseInfo -> caseInfo.Name
| FSharpUnionCase.Typed typ -> printType typ
)
|> String.concat ", "

let option =
if info.IsOptional then
Expand Down Expand Up @@ -891,9 +897,14 @@ let rec print (printer: Printer) (fsharpTypes: FSharpType list) =
|> List.iter (fun enumCaseInfo ->
printer.Write($"""| """)

printInlineAttributes printer enumCaseInfo.Attributes
match enumCaseInfo with
| FSharpUnionCase.Named enumCaseInfo ->
printInlineAttributes printer enumCaseInfo.Attributes

printer.WriteInline(enumCaseInfo.Name)
printer.WriteInline(enumCaseInfo.Name)
| FSharpUnionCase.Typed typ ->
printer.WriteInline(printType typ)
printer.NewLine

printer.NewLine
)
Expand Down
40 changes: 7 additions & 33 deletions src/Glutinum.Converter/Reader/UnionTypeNode.fs
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,6 @@ let rec private readUnionTypeCases
)
symbolOpt

let readTypeReference () =
({
Name = typeReferenceNode.getText ()
FullName = checker.getFullyQualifiedName symbol
TypeArguments = []
})
|> GlueType.TypeReference
|> List.singleton
|> Some

// TODO: How to differentiate TypeReference to Enum/Union vs others
// Check below is really hacky / not robust
match symbol.declarations with
Expand All @@ -101,19 +91,10 @@ let rec private readUnionTypeCases
|> List.singleton
|> Some
else if isFromEs5Lib symbolOpt then
match
getFullNameOrEmpty
checker
(!!typeReferenceNode.typeName)
with
| "Record" ->
TypeNode.UtilityType.readRecord
reader
typeReferenceNode
|> List.singleton
|> Some
reader.ReadTypeNode typeReferenceNode
|> List.singleton
|> Some

| _ -> readTypeReference ()
else
let declaration = declarations.[0]
// TODO: This is an optimitic approach
Expand All @@ -122,7 +103,10 @@ let rec private readUnionTypeCases
| Ts.SyntaxKind.TypeAliasDeclaration ->
reader.ReadNode declaration |> List.singleton |> Some

| _ -> readTypeReference ()
| _ ->
reader.ReadTypeNode typeReferenceNode
|> List.singleton
|> Some

| None ->
let typ = checker.getTypeOfSymbol symbol
Expand All @@ -140,16 +124,6 @@ let rec private readUnionTypeCases
typeReferenceNode
)

// else
// symbol.declarations
// |> Seq.toList
// |> List.collect (fun declaration ->
// // We use the readUnionType to handle nested unions
// let enum = readUnionType checker declaration?``type``

// [ enum ]
// )
// |> Some
else
match node.kind with
| Ts.SyntaxKind.UnionType ->
Expand Down
30 changes: 7 additions & 23 deletions src/Glutinum.Converter/Transform.fs
Original file line number Diff line number Diff line change
Expand Up @@ -358,26 +358,9 @@ let rec private transformType
let cases =
others
|> List.mapi (fun index caseType ->
let name, context =
sanitizeNameAndPushScope
$"Case%i{index + 1}"
context

let caseTypeName =
match caseType with
| GlueType.Record recordInfo ->
transformRecord context name [] recordInfo
|> context.ExposeType

context.FullName
| caseType -> caseType.Name
let context = context.PushScope $"Case%i{index + 1}"

{
Attributes = []
Name =
Naming.mapTypeNameToFableCoreAwareName
caseTypeName
}
transformType context caseType |> FSharpUnionCase.Typed
)

{
Expand Down Expand Up @@ -1364,6 +1347,7 @@ let private transformEnum (glueEnum: GlueEnum) : FSharpType =
]
Name = caseName
}
|> FSharpUnionCase.Named

{
Attributes =
Expand Down Expand Up @@ -1415,7 +1399,7 @@ module TypeAliasDeclaration =
]
Name = sanitizeResult.Name
}
: FSharpUnionCase
|> FSharpUnionCase.Named
|> Some
// Doesn't make sense to have a case for call signature
| GlueMember.CallSignature _
Expand Down Expand Up @@ -1480,8 +1464,8 @@ module TypeAliasDeclaration =
({
Attributes = []
Name = Naming.sanitizeName value
}
: FSharpUnionCase)
}
|> FSharpUnionCase.Named)

({
Attributes =
Expand Down Expand Up @@ -1645,7 +1629,7 @@ let private tryOptimizeUnionType
]
Name = sanitizeResult.Name
}
: FSharpUnionCase
|> FSharpUnionCase.Named
| _ -> failwith "Should not happen"
)
|> List.distinct
Expand Down
14 changes: 11 additions & 3 deletions src/Glutinum.Web/Pages/Editors.FSharpAST.FSharpASTViewer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,18 @@ type FSharpASTViewer =

static member private UnionCases(cases: FSharpUnionCase list) =
cases
|> List.map (fun case_ ->
|> List.map (fun case ->
ASTViewer.renderNode "FSharpUnionCase" [
FSharpASTViewer.Name case_.Name
FSharpASTViewer.Attributes case_.Attributes
match case with
| FSharpUnionCase.Named caseInfo ->
ASTViewer.renderNode "Named" [
FSharpASTViewer.Name caseInfo.Name
FSharpASTViewer.Attributes caseInfo.Attributes
]
| FSharpUnionCase.Typed typ ->
ASTViewer.renderNode "Typed" [
FSharpASTViewer.FSharpType typ
]
]
)
|> ASTViewer.renderNode "Cases"
Expand Down
5 changes: 5 additions & 0 deletions tests/specs/references/unionType/withTypeParameter.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class MyType<TResult1> {
a : TResult1
}

type T<TResult1> = TResult1 | MyType<TResult1>
23 changes: 23 additions & 0 deletions tests/specs/references/unionType/withTypeParameter.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module rec Glutinum

open Fable.Core
open Fable.Core.JsInterop
open System

[<AbstractClass>]
[<Erase>]
type Exports =
[<Import("MyType", "REPLACE_ME_WITH_MODULE_NAME"); EmitConstructor>]
static member MyType<'TResult1> () : MyType<'TResult1> = nativeOnly

[<AllowNullLiteral>]
[<Interface>]
type MyType<'TResult1> =
abstract member a: 'TResult1 with get, set

type T<'TResult1> =
U2<'TResult1, MyType<'TResult1>>

(***)
#r "nuget: Fable.Core"
(***)

0 comments on commit cc99bab

Please sign in to comment.