From e4426589c38ee20e6caa657ccdf2ca5ca14b42bd Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Mon, 20 Nov 2023 19:21:01 +0100 Subject: [PATCH 1/2] GenType: fix issue with @as("0") and other numbers. There is some special code in the type emitter to take care of poly variants of the form e.g. `#0`, which is represented internally as the string "0". This conflicts with normal variants annotated with `@as("0")` and such. This PR resolves the case of numeric poly variants early on, and removes the special casing in the code emitter. Fixes https://github.com/rescript-lang/rescript-compiler/issues/6486 --- CHANGELOG.md | 1 + jscomp/gentype/GenTypeCommon.ml | 33 +++++++++---------- jscomp/gentype/TranslateCoreType.ml | 13 ++++++-- jscomp/gentype/TranslateTypeDeclarations.ml | 21 ++++++++---- jscomp/gentype/TranslateTypeExprFromTypes.ml | 8 ++++- .../package-lock.json | 2 +- .../src/Unboxed.bs.js | 9 +++++ .../src/Unboxed.gen.tsx | 8 +++++ .../typescript-react-example/src/Unboxed.res | 14 +++++++- 9 files changed, 81 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b721e273c3..74f0cdda71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - Fix issue with GenType and `result` introduced in rc.5. https://github.com/rescript-lang/rescript-compiler/pull/6464 - Fix compiler crash when inlining complex constants in pattern matching. https://github.com/rescript-lang/rescript-compiler/pull/6471 - Fix issue with generating async functions inside loops. https://github.com/rescript-lang/rescript-compiler/pull/6479 +- Fix issue with Gentype and string annotations with numbers such as `@as("0")`. https://github.com/rescript-lang/rescript-compiler/pull/6487 # 11.0.0-rc.5 diff --git a/jscomp/gentype/GenTypeCommon.ml b/jscomp/gentype/GenTypeCommon.ml index 3264ba7bf0..4e7258e181 100644 --- a/jscomp/gentype/GenTypeCommon.ml +++ b/jscomp/gentype/GenTypeCommon.ml @@ -38,30 +38,29 @@ let isJSSafePropertyName name = | 'A' .. 'z' | '0' .. '9' -> true | _ -> false) +let isNumber s = + let len = String.length s in + len > 0 + && (match len > 1 with + | true -> (s.[0] [@doesNotRaise]) > '0' + | false -> true) + && + let res = ref true in + for i = 0 to len - 1 do + match s.[i] [@doesNotRaise] with + | '0' .. '9' -> () + | _ -> res := false + done; + res.contents + let labelJSToString case = - let isNumber s = - let len = String.length s in - len > 0 - && (match len > 1 with - | true -> (s.[0] [@doesNotRaise]) > '0' - | false -> true) - && - let res = ref true in - for i = 0 to len - 1 do - match s.[i] [@doesNotRaise] with - | '0' .. '9' -> () - | _ -> res := false - done; - res.contents - in match case.labelJS with | NullLabel -> "null" | UndefinedLabel -> "undefined" | BoolLabel b -> b |> string_of_bool | FloatLabel s -> s | IntLabel i -> i - | StringLabel s -> - if s = case.label && isNumber s then s else s |> EmitText.quotes + | StringLabel s -> s |> EmitText.quotes type closedFlag = Open | Closed diff --git a/jscomp/gentype/TranslateCoreType.ml b/jscomp/gentype/TranslateCoreType.ml index 33ee6cd847..384df3e170 100644 --- a/jscomp/gentype/TranslateCoreType.ml +++ b/jscomp/gentype/TranslateCoreType.ml @@ -178,7 +178,9 @@ and translateCoreType_ ~config ~typeVarsGen if asString then match attributes |> Annotation.getAsString with | Some labelRenamed -> StringLabel labelRenamed - | None -> StringLabel label + | None -> + if isNumber label then IntLabel label + else StringLabel label else if asInt then ( match attributes |> Annotation.getAsInt with | Some n -> @@ -187,6 +189,7 @@ and translateCoreType_ ~config ~typeVarsGen | None -> lastBsInt := !lastBsInt + 1; IntLabel (string_of_int !lastBsInt)) + else if isNumber label then IntLabel label else StringLabel label in {label; labelJS}) @@ -202,7 +205,13 @@ and translateCoreType_ ~config ~typeVarsGen payloadsTranslations |> List.map (fun (label, _attributes, translation) -> { - case = {label; labelJS = StringLabel label}; + case = + { + label; + labelJS = + (if isNumber label then IntLabel label + else StringLabel label); + }; t = translation.type_; }) in diff --git a/jscomp/gentype/TranslateTypeDeclarations.ml b/jscomp/gentype/TranslateTypeDeclarations.ml index a11c066391..5e57a01d4b 100644 --- a/jscomp/gentype/TranslateTypeDeclarations.ml +++ b/jscomp/gentype/TranslateTypeDeclarations.ml @@ -21,7 +21,7 @@ let createExportTypeFromTypeDeclaration ~annotation ~loc ~nameAs ~opaque ~type_ annotation; } -let createCase (label, attributes) = +let createCase (label, attributes) ~poly = { label; labelJS = @@ -34,7 +34,8 @@ let createCase (label, attributes) = | Some (_, FloatPayload s) -> FloatLabel s | Some (_, IntPayload i) -> IntLabel i | Some (_, StringPayload asLabel) -> StringLabel asLabel - | _ -> StringLabel label); + | _ -> + if poly && isNumber label then IntLabel label else StringLabel label); } (** @@ -190,7 +191,9 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver match (coreType, translation.type_) with | {ctyp_desc = Ttyp_variant (rowFields, _, _)}, Variant variant -> let rowFieldsVariants = rowFields |> TranslateCoreType.processVariant in - let noPayloads = rowFieldsVariants.noPayloads |> List.map createCase in + let noPayloads = + rowFieldsVariants.noPayloads |> List.map (createCase ~poly:true) + in let payloads = if variant.payloads |> List.length @@ -199,7 +202,7 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver (List.combine variant.payloads rowFieldsVariants.payloads [@doesNotRaise]) |> List.map (fun (payload, (label, attributes, _)) -> - let case = (label, attributes) |> createCase in + let case = (label, attributes) |> createCase ~poly:true in {payload with case}) else variant.payloads in @@ -277,7 +280,10 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver variantsNoPayload |> List.map (fun (name, attributes, _argTypes, _importTypes, recordValue) -> - {((name, attributes) |> createCase) with label = recordValue}) + { + ((name, attributes) |> createCase ~poly:false) with + label = recordValue; + }) in let payloads = variantsWithPayload @@ -290,7 +296,10 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver in { case = - {((name, attributes) |> createCase) with label = recordValue}; + { + ((name, attributes) |> createCase ~poly:false) with + label = recordValue; + }; t = type_; }) in diff --git a/jscomp/gentype/TranslateTypeExprFromTypes.ml b/jscomp/gentype/TranslateTypeExprFromTypes.ml index a42cc6bb87..30fff9432e 100644 --- a/jscomp/gentype/TranslateTypeExprFromTypes.ml +++ b/jscomp/gentype/TranslateTypeExprFromTypes.ml @@ -382,7 +382,13 @@ and translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv | {noPayloads; payloads = []; unknowns = []} -> let noPayloads = noPayloads - |> List.map (fun label -> {label; labelJS = StringLabel label}) + |> List.map (fun label -> + { + label; + labelJS = + (if isNumber label then IntLabel label + else StringLabel label); + }) in let type_ = createVariant ~inherits:[] ~noPayloads ~payloads:[] ~polymorphic:true diff --git a/jscomp/gentype_tests/typescript-react-example/package-lock.json b/jscomp/gentype_tests/typescript-react-example/package-lock.json index 0a527573b2..7aafa5a701 100644 --- a/jscomp/gentype_tests/typescript-react-example/package-lock.json +++ b/jscomp/gentype_tests/typescript-react-example/package-lock.json @@ -24,7 +24,7 @@ }, "../../..": { "name": "rescript", - "version": "11.0.0-rc.5", + "version": "11.0.0-rc.6", "dev": true, "hasInstallScript": true, "license": "SEE LICENSE IN LICENSE", diff --git a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.bs.js b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.bs.js index 1793e16153..7c02bf0833 100644 --- a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.bs.js +++ b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.bs.js @@ -9,8 +9,17 @@ function r2Test(x) { return x; } +var a = "0"; + +var b = "1"; + +var zero = 0; + export { testV1 , r2Test , + a , + b , + zero , } /* No side effect */ diff --git a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx index ae18d4863d..ac06ec9739 100644 --- a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx +++ b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx @@ -16,6 +16,14 @@ export type r2 = string; export type t = number[] | number | ((_1:number) => number); +export type tabIndex = "0" | "1"; + export const testV1: (x:v1) => v1 = UnboxedBS.testV1; export const r2Test: (x:r2) => r2 = UnboxedBS.r2Test; + +export const a: tabIndex = UnboxedBS.a; + +export const b: tabIndex = UnboxedBS.b; + +export const zero: 0 = UnboxedBS.zero; diff --git a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res index 851ebc4349..f4274c2064 100644 --- a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res +++ b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res @@ -15,4 +15,16 @@ type r2 = B({g: string}) @genType let r2Test = (x: r2) => x @genType @unboxed -type t = Array(array) | Record({x:int}) | Function((. int) => int) +type t = Array(array) | Record({x: int}) | Function((. int) => int) + +@genType +type tabIndex = | @as("0") Activity | @as("1") UserKeyword + +@genType +let a = Activity + +@genType +let b = UserKeyword + +@genType +let zero = #0 From aee8ff0695325ac5c48b71bbb9242656134bf10a Mon Sep 17 00:00:00 2001 From: Cristiano Calcagno Date: Tue, 21 Nov 2023 08:33:49 +0100 Subject: [PATCH 2/2] Add test with zero. --- .../gentype_tests/typescript-react-example/src/Unboxed.gen.tsx | 2 +- jscomp/gentype_tests/typescript-react-example/src/Unboxed.res | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx index ac06ec9739..71d4f6119d 100644 --- a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx +++ b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.gen.tsx @@ -16,7 +16,7 @@ export type r2 = string; export type t = number[] | number | ((_1:number) => number); -export type tabIndex = "0" | "1"; +export type tabIndex = "0" | "1" | 0; export const testV1: (x:v1) => v1 = UnboxedBS.testV1; diff --git a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res index f4274c2064..ee98bc17c5 100644 --- a/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res +++ b/jscomp/gentype_tests/typescript-react-example/src/Unboxed.res @@ -18,7 +18,7 @@ type r2 = B({g: string}) type t = Array(array) | Record({x: int}) | Function((. int) => int) @genType -type tabIndex = | @as("0") Activity | @as("1") UserKeyword +type tabIndex = | @as("0") Activity | @as("1") UserKeyword | @as(0) NumZero @genType let a = Activity