Skip to content

Experiment with allowing empty inline records #6494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@

# 11.0.0-rc.7 (Unreleased)

#### :rocket: New Feature

- Allow empty inline records in variants. https://github.com/rescript-lang/rescript-compiler/pull/6494
- Allow empty record patterns in pattern matching. https://github.com/rescript-lang/rescript-compiler/pull/6494

# 11.0.0-rc.6

#### :rocket: New Feature
Expand Down
3 changes: 0 additions & 3 deletions jscomp/frontend/bs_ast_invariant.ml
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,6 @@ let emit_external_warnings : iterator =
(fun self (pat : Parsetree.pattern) ->
match pat.ppat_desc with
| Ppat_constant constant -> check_constant pat.ppat_loc constant
| Ppat_record ([], _) ->
Location.raise_errorf ~loc:pat.ppat_loc
"Empty record pattern is not supported"
| _ -> super.pat self pat);
}

Expand Down
2 changes: 1 addition & 1 deletion jscomp/gentype/GenTypeCommon.ml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type labelJS =
| IntLabel of string
| StringLabel of string

type case = {label: string; labelJS: labelJS}
type case = {labelJS: labelJS}

let isJSSafePropertyName name =
name = ""
Expand Down
15 changes: 0 additions & 15 deletions jscomp/gentype/Runtime.ml
Original file line number Diff line number Diff line change
@@ -1,21 +1,6 @@
type recordGen = {mutable unboxed: int; mutable boxed: int}
type recordValue = int
type moduleItem = string
type moduleAccessPath = Root of string | Dot of moduleAccessPath * moduleItem

let recordValueToString recordValue = recordValue |> string_of_int
let recordGen () = {unboxed = 0; boxed = 0}

let newRecordValue ~unboxed recordGen =
if unboxed then (
let v = recordGen.unboxed in
recordGen.unboxed <- recordGen.unboxed + 1;
v)
else
let v = recordGen.boxed in
recordGen.boxed <- recordGen.boxed + 1;
v

let newModuleItem ~name = name

let rec emitModuleAccessPath ~config moduleAccessPath =
Expand Down
5 changes: 0 additions & 5 deletions jscomp/gentype/Runtime.mli
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
open GenTypeCommon

type recordGen
type recordValue
type moduleItem
type moduleAccessPath = Root of string | Dot of moduleAccessPath * moduleItem

Expand All @@ -11,9 +9,6 @@ val emitModuleAccessPath : config:Config.t -> moduleAccessPath -> string

val isMutableObjectField : string -> bool
val newModuleItem : name:string -> moduleItem
val newRecordValue : unboxed:bool -> recordGen -> recordValue
val recordGen : unit -> recordGen
val recordValueToString : recordValue -> string
val jsVariantTag : polymorphic:bool -> tag:string option -> string
val jsVariantPayloadTag : n:int -> string
val jsVariantValue : polymorphic:bool -> string
3 changes: 1 addition & 2 deletions jscomp/gentype/TranslateCoreType.ml
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ and translateCoreType_ ~config ~typeVarsGen
else if isNumber label then IntLabel label
else StringLabel label
in
{label; labelJS})
{labelJS})
in
let payloadsTranslations =
payloads
Expand All @@ -207,7 +207,6 @@ and translateCoreType_ ~config ~typeVarsGen
{
case =
{
label;
labelJS =
(if isNumber label then IntLabel label
else StringLabel label);
Expand Down
37 changes: 7 additions & 30 deletions jscomp/gentype/TranslateTypeDeclarations.ml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ let createExportTypeFromTypeDeclaration ~annotation ~loc ~nameAs ~opaque ~type_

let createCase (label, attributes) ~poly =
{
label;
labelJS =
(match
attributes |> Annotation.getAttributePayload Annotation.tagIsAs
Expand Down Expand Up @@ -230,7 +229,6 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver
}
|> returnTypeDeclaration
| VariantDeclarationFromTypes constructorDeclarations, None ->
let recordGen = Runtime.recordGen () in
let variants =
constructorDeclarations
|> List.map (fun constructorDeclaration ->
Expand Down Expand Up @@ -262,46 +260,25 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver
|> Translation.translateDependencies ~config ~outputFileRelative
~resolver
in
let recordValue =
recordGen
|> Runtime.newRecordValue
~unboxed:(constructorArgs = Cstr_tuple [])
in
( name,
attributes,
argTypes,
importTypes,
recordValue |> Runtime.recordValueToString ))
(name, attributes, argTypes, importTypes))
in
let variantsNoPayload, variantsWithPayload =
variants |> List.partition (fun (_, _, argTypes, _, _) -> argTypes = [])
variants |> List.partition (fun (_, _, argTypes, _) -> argTypes = [])
in
let noPayloads =
variantsNoPayload
|> List.map
(fun (name, attributes, _argTypes, _importTypes, recordValue) ->
{
((name, attributes) |> createCase ~poly:false) with
label = recordValue;
})
|> List.map (fun (name, attributes, _argTypes, _importTypes) ->
(name, attributes) |> createCase ~poly:false)
in
let payloads =
variantsWithPayload
|> List.map
(fun (name, attributes, argTypes, _importTypes, recordValue) ->
|> List.map (fun (name, attributes, argTypes, _importTypes) ->
let type_ =
match argTypes with
| [type_] -> type_
| _ -> Tuple argTypes
in
{
case =
{
((name, attributes) |> createCase ~poly:false) with
label = recordValue;
};
t = type_;
})
{case = (name, attributes) |> createCase ~poly:false; t = type_})
in
let variantTyp =
createVariant ~inherits:[] ~noPayloads ~payloads ~polymorphic:false
Expand All @@ -325,7 +302,7 @@ let traslateDeclarationKind ~config ~loc ~outputFileRelative ~resolver
in
let importTypes =
variants
|> List.map (fun (_, _, _, importTypes, _) -> importTypes)
|> List.map (fun (_, _, _, importTypes) -> importTypes)
|> List.concat
in
{CodeItem.exportFromTypeDeclaration; importTypes} |> returnTypeDeclaration
Expand Down
17 changes: 5 additions & 12 deletions jscomp/gentype/TranslateTypeExprFromTypes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,13 @@ let translateConstr ~config ~paramsTranslation ~(path : Path.t) ~typeEnv =
}
| ( (["Pervasives"; "result"] | ["Belt"; "Result"; "t"] | ["result"]),
[paramTranslation1; paramTranslation2] ) ->
let case n name type_ =
{case = {label = string_of_int n; labelJS = StringLabel name}; t = type_}
in
let case name type_ = {case = {labelJS = StringLabel name}; t = type_} in
let variant =
createVariant ~inherits:[] ~noPayloads:[]
~payloads:
[
case 0 "Ok" paramTranslation1.type_;
case 1 "Error" paramTranslation2.type_;
case "Ok" paramTranslation1.type_;
case "Error" paramTranslation2.type_;
]
~polymorphic:false ~tag:None ~unboxed:false
in
Expand Down Expand Up @@ -384,7 +382,6 @@ and translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv
noPayloads
|> List.map (fun label ->
{
label;
labelJS =
(if isNumber label then IntLabel label
else StringLabel label);
Expand All @@ -401,8 +398,7 @@ and translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv
t |> translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv
| {noPayloads; payloads; unknowns = []} ->
let noPayloads =
noPayloads
|> List.map (fun label -> {label; labelJS = StringLabel label})
noPayloads |> List.map (fun label -> {labelJS = StringLabel label})
in
let payloadTranslations =
payloads
Expand All @@ -414,10 +410,7 @@ and translateTypeExprFromTypes_ ~config ~typeVarsGen ~typeEnv
let payloads =
payloadTranslations
|> List.map (fun (label, translation) ->
{
case = {label; labelJS = StringLabel label};
t = translation.type_;
})
{case = {labelJS = StringLabel label}; t = translation.type_})
in
let type_ =
createVariant ~inherits:[] ~noPayloads ~payloads ~polymorphic:true
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion jscomp/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1273,7 +1273,6 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
| _ -> k None
end
| Ppat_record(lid_sp_list, closed) ->
assert (lid_sp_list <> []);
let opath, record_ty =
try
let (p0, p, _, _) = extract_concrete_record !env expected_ty in
Expand Down
9 changes: 0 additions & 9 deletions jscomp/syntax/src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4544,7 +4544,6 @@ and parseConstrDeclArgs p =
(* TODO: this could use some cleanup/stratification *)
match p.Parser.token with
| Lbrace -> (
let lbrace = p.startPos in
Parser.next p;
let startPos = p.Parser.startPos in
match p.Parser.token with
Expand Down Expand Up @@ -4683,14 +4682,6 @@ and parseConstrDeclArgs p =
:: parseCommaDelimitedRegion ~grammar:Grammar.FieldDeclarations
~closing:Rbrace ~f:parseFieldDeclarationRegion p
in
let () =
match fields with
| [] ->
Parser.err ~startPos:lbrace p
(Diagnostics.message
"An inline record declaration needs at least one field")
| _ -> ()
in
Parser.expect Rbrace p;
Parser.optional p Comma |> ignore;
Parser.expect Rparen p;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,3 @@

Syntax error!
tests/parsing/errors/typeDef/emptyInlineRecord.res:3:10-11

1 │ type node<'a> =
2 │ | Nil
3 │ | Node({})
4 │

An inline record declaration needs at least one field

type nonrec 'a node =
| Nil
| Node of {
Expand Down
18 changes: 18 additions & 0 deletions jscomp/test/inline_record_test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions jscomp/test/inline_record_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,20 @@ let ff1 = (x: t1): t1 =>
}

let () = Mt.from_pair_suites(__MODULE__, suites.contents)

type emptyRecord = A | B({})

let b = B({})

let () = switch b {
| A => Js.log("A!")
| B({}) => Js.log("B")
}

type r = {y: int}
let r = {y: 10}

switch r {
| {y: 10} => Js.log("10!")
| {} => Js.log("Catch all?")
}