Skip to content

Commit b26bede

Browse files
cknittcristianoc
andauthored
10.1_release -> master (#5855)
* Print error message when `?` is used for non-optional fields. * Add CHANGELOG entry * Set version to 10.1.0 (#5848) Co-authored-by: Cristiano Calcagno <[email protected]>
1 parent 4e95019 commit b26bede

File tree

8 files changed

+118
-65
lines changed

8 files changed

+118
-65
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ These are only breaking changes for unformatted code.
5656
- Process `@set` annotation for field update as generating an uncurried function https://github.com/rescript-lang/rescript-compiler/pull/5846
5757
- Treat uncurried application of primitives like curried application, which produces better output https://github.com/rescript-lang/rescript-compiler/pull/5851
5858

59-
# 10.1.0-rc.6
59+
# 10.1.0
6060

6161
#### :bug: Bug Fix
6262

63+
- Fix issue where no error was reported when ? was used for non-optional fields. https://github.com/rescript-lang/rescript-compiler/pull/5853
6364
- Fix issue where optional fields in inline records were not supported and would cause type errors https://github.com/rescript-lang/rescript-compiler/pull/5827
6465

6566
# 10.1.0-rc.5
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/fieldNotOptional.res:3:19
4+
5+
1 │ type r = {nonopt: int, opt?: string}
6+
2 │
7+
3 │ let v = {nonopt: ?3, opt: ?None}
8+
4 │
9+
5 │ let f = r =>
10+
11+
Field nonopt is not optional in type r. Use without ?
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
type r = {nonopt: int, opt?: string}
2+
3+
let v = {nonopt: ?3, opt: ?None}
4+
5+
let f = r =>
6+
switch r {
7+
| {nonopt: ?_, opt: ?_} => true
8+
}
9+
10+
type inline = A({nonopt: int, opt?: string})
11+
12+
let vi = A({nonopt: ?3, opt: ?None})
13+
14+
let fi = a =>
15+
switch a {
16+
| A ({nonopt: ?_, opt: ?_}) => true
17+
}

jscomp/ml/typecore.ml

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ type error =
7474
| Labels_omitted of string list
7575
| Empty_record_literal
7676
| Uncurried_arity_mismatch of type_expr * int * int
77+
| Field_not_optional of string * type_expr
7778
exception Error of Location.t * Env.t * error
7879
exception Error_forward of Location.error
7980

@@ -309,6 +310,19 @@ let extract_concrete_variant env ty =
309310
| (p0, p, {type_kind=Type_open}) -> (p0, p, [])
310311
| _ -> raise Not_found
311312

313+
let label_is_optional ld =
314+
match ld.lbl_repres with
315+
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
316+
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
317+
| _ -> false
318+
319+
let check_optional_attr env ld attrs loc =
320+
let check_redundant () =
321+
if not (label_is_optional ld) then
322+
raise (Error (loc, env, Field_not_optional (ld.lbl_name, ld.lbl_res)));
323+
true in
324+
Ext_list.exists attrs (fun ({txt}, _) ->
325+
txt = "ns.optional" && check_redundant ())
312326

313327
(* unification inside type_pat*)
314328
let unify_pat_types loc env ty ty' =
@@ -1151,15 +1165,8 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
11511165
Some (p0, p), expected_ty
11521166
with Not_found -> None, newvar ()
11531167
in
1154-
let label_is_optional ld =
1155-
match ld.lbl_repres with
1156-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
1157-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
1158-
| _ -> false in
11591168
let process_optional_label (ld, pat) =
1160-
let exp_optional_attr =
1161-
Ext_list.exists pat.ppat_attributes (fun ({txt },_) -> txt = "ns.optional")
1162-
in
1169+
let exp_optional_attr = check_optional_attr !env ld pat.ppat_attributes pat.ppat_loc in
11631170
let isFromPamatch = match pat.ppat_desc with
11641171
| Ppat_construct ({txt = Lident s}, _) ->
11651172
String.length s >= 2 && s.[0] = '#' && s.[1] = '$'
@@ -1878,15 +1885,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
18781885
unify_exp env (re exp) (instance env ty_expected);
18791886
exp
18801887
in
1881-
let label_is_optional ld =
1882-
match ld.lbl_repres with
1883-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
1884-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
1885-
| _ -> false in
18861888
let process_optional_label (id, ld, e) =
1887-
let exp_optional_attr =
1888-
Ext_list.exists e.pexp_attributes (fun ({txt },_) -> txt = "ns.optional")
1889-
in
1889+
let exp_optional_attr = check_optional_attr env ld e.pexp_attributes e.pexp_loc in
18901890
if label_is_optional ld && not exp_optional_attr then
18911891
let lid = mknoloc (Longident.(Ldot (Lident "*predef*", "Some"))) in
18921892
let e = Ast_helper.Exp.construct ~loc:e.pexp_loc lid (Some e)
@@ -3876,6 +3876,11 @@ let report_error env ppf = function
38763876
type_expr typ;
38773877
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
38783878
args (if args = 0 then "" else "s") arity
3879+
| Field_not_optional (name, typ) ->
3880+
fprintf ppf
3881+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
3882+
type_expr typ
3883+
38793884
38803885
let super_report_error_no_wrap_printing_env = report_error
38813886

jscomp/ml/typecore.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ type error =
110110
| Labels_omitted of string list
111111
| Empty_record_literal
112112
| Uncurried_arity_mismatch of type_expr * int * int
113+
| Field_not_optional of string * type_expr
113114
exception Error of Location.t * Env.t * error
114115
exception Error_forward of Location.error
115116

lib/4.06.1/unstable/js_compiler.ml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40696,6 +40696,7 @@ type error =
4069640696
| Labels_omitted of string list
4069740697
| Empty_record_literal
4069840698
| Uncurried_arity_mismatch of type_expr * int * int
40699+
| Field_not_optional of string * type_expr
4069940700
exception Error of Location.t * Env.t * error
4070040701
exception Error_forward of Location.error
4070140702

@@ -40804,6 +40805,7 @@ type error =
4080440805
| Labels_omitted of string list
4080540806
| Empty_record_literal
4080640807
| Uncurried_arity_mismatch of type_expr * int * int
40808+
| Field_not_optional of string * type_expr
4080740809
exception Error of Location.t * Env.t * error
4080840810
exception Error_forward of Location.error
4080940811

@@ -41039,6 +41041,19 @@ let extract_concrete_variant env ty =
4103941041
| (p0, p, {type_kind=Type_open}) -> (p0, p, [])
4104041042
| _ -> raise Not_found
4104141043

41044+
let label_is_optional ld =
41045+
match ld.lbl_repres with
41046+
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
41047+
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
41048+
| _ -> false
41049+
41050+
let check_optional_attr env ld attrs loc =
41051+
let check_redundant () =
41052+
if not (label_is_optional ld) then
41053+
raise (Error (loc, env, Field_not_optional (ld.lbl_name, ld.lbl_res)));
41054+
true in
41055+
Ext_list.exists attrs (fun ({txt}, _) ->
41056+
txt = "ns.optional" && check_redundant ())
4104241057

4104341058
(* unification inside type_pat*)
4104441059
let unify_pat_types loc env ty ty' =
@@ -41881,15 +41896,8 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
4188141896
Some (p0, p), expected_ty
4188241897
with Not_found -> None, newvar ()
4188341898
in
41884-
let label_is_optional ld =
41885-
match ld.lbl_repres with
41886-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
41887-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
41888-
| _ -> false in
4188941899
let process_optional_label (ld, pat) =
41890-
let exp_optional_attr =
41891-
Ext_list.exists pat.ppat_attributes (fun ({txt },_) -> txt = "ns.optional")
41892-
in
41900+
let exp_optional_attr = check_optional_attr !env ld pat.ppat_attributes pat.ppat_loc in
4189341901
let isFromPamatch = match pat.ppat_desc with
4189441902
| Ppat_construct ({txt = Lident s}, _) ->
4189541903
String.length s >= 2 && s.[0] = '#' && s.[1] = '$'
@@ -42608,15 +42616,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
4260842616
unify_exp env (re exp) (instance env ty_expected);
4260942617
exp
4261042618
in
42611-
let label_is_optional ld =
42612-
match ld.lbl_repres with
42613-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
42614-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
42615-
| _ -> false in
4261642619
let process_optional_label (id, ld, e) =
42617-
let exp_optional_attr =
42618-
Ext_list.exists e.pexp_attributes (fun ({txt },_) -> txt = "ns.optional")
42619-
in
42620+
let exp_optional_attr = check_optional_attr env ld e.pexp_attributes e.pexp_loc in
4262042621
if label_is_optional ld && not exp_optional_attr then
4262142622
let lid = mknoloc (Longident.(Ldot (Lident "*predef*", "Some"))) in
4262242623
let e = Ast_helper.Exp.construct ~loc:e.pexp_loc lid (Some e)
@@ -44606,6 +44607,11 @@ let report_error env ppf = function
4460644607
type_expr typ;
4460744608
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
4460844609
args (if args = 0 then "" else "s") arity
44610+
| Field_not_optional (name, typ) ->
44611+
fprintf ppf
44612+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
44613+
type_expr typ
44614+
4460944615

4461044616
let super_report_error_no_wrap_printing_env = report_error
4461144617

lib/4.06.1/unstable/js_playground_compiler.ml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40696,6 +40696,7 @@ type error =
4069640696
| Labels_omitted of string list
4069740697
| Empty_record_literal
4069840698
| Uncurried_arity_mismatch of type_expr * int * int
40699+
| Field_not_optional of string * type_expr
4069940700
exception Error of Location.t * Env.t * error
4070040701
exception Error_forward of Location.error
4070140702

@@ -40804,6 +40805,7 @@ type error =
4080440805
| Labels_omitted of string list
4080540806
| Empty_record_literal
4080640807
| Uncurried_arity_mismatch of type_expr * int * int
40808+
| Field_not_optional of string * type_expr
4080740809
exception Error of Location.t * Env.t * error
4080840810
exception Error_forward of Location.error
4080940811

@@ -41039,6 +41041,19 @@ let extract_concrete_variant env ty =
4103941041
| (p0, p, {type_kind=Type_open}) -> (p0, p, [])
4104041042
| _ -> raise Not_found
4104141043

41044+
let label_is_optional ld =
41045+
match ld.lbl_repres with
41046+
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
41047+
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
41048+
| _ -> false
41049+
41050+
let check_optional_attr env ld attrs loc =
41051+
let check_redundant () =
41052+
if not (label_is_optional ld) then
41053+
raise (Error (loc, env, Field_not_optional (ld.lbl_name, ld.lbl_res)));
41054+
true in
41055+
Ext_list.exists attrs (fun ({txt}, _) ->
41056+
txt = "ns.optional" && check_redundant ())
4104241057

4104341058
(* unification inside type_pat*)
4104441059
let unify_pat_types loc env ty ty' =
@@ -41881,15 +41896,8 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
4188141896
Some (p0, p), expected_ty
4188241897
with Not_found -> None, newvar ()
4188341898
in
41884-
let label_is_optional ld =
41885-
match ld.lbl_repres with
41886-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
41887-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
41888-
| _ -> false in
4188941899
let process_optional_label (ld, pat) =
41890-
let exp_optional_attr =
41891-
Ext_list.exists pat.ppat_attributes (fun ({txt },_) -> txt = "ns.optional")
41892-
in
41900+
let exp_optional_attr = check_optional_attr !env ld pat.ppat_attributes pat.ppat_loc in
4189341901
let isFromPamatch = match pat.ppat_desc with
4189441902
| Ppat_construct ({txt = Lident s}, _) ->
4189541903
String.length s >= 2 && s.[0] = '#' && s.[1] = '$'
@@ -42608,15 +42616,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
4260842616
unify_exp env (re exp) (instance env ty_expected);
4260942617
exp
4261042618
in
42611-
let label_is_optional ld =
42612-
match ld.lbl_repres with
42613-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
42614-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
42615-
| _ -> false in
4261642619
let process_optional_label (id, ld, e) =
42617-
let exp_optional_attr =
42618-
Ext_list.exists e.pexp_attributes (fun ({txt },_) -> txt = "ns.optional")
42619-
in
42620+
let exp_optional_attr = check_optional_attr env ld e.pexp_attributes e.pexp_loc in
4262042621
if label_is_optional ld && not exp_optional_attr then
4262142622
let lid = mknoloc (Longident.(Ldot (Lident "*predef*", "Some"))) in
4262242623
let e = Ast_helper.Exp.construct ~loc:e.pexp_loc lid (Some e)
@@ -44606,6 +44607,11 @@ let report_error env ppf = function
4460644607
type_expr typ;
4460744608
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
4460844609
args (if args = 0 then "" else "s") arity
44610+
| Field_not_optional (name, typ) ->
44611+
fprintf ppf
44612+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
44613+
type_expr typ
44614+
4460944615

4461044616
let super_report_error_no_wrap_printing_env = report_error
4461144617

lib/4.06.1/whole_compiler.ml

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95690,6 +95690,7 @@ type error =
9569095690
| Labels_omitted of string list
9569195691
| Empty_record_literal
9569295692
| Uncurried_arity_mismatch of type_expr * int * int
95693+
| Field_not_optional of string * type_expr
9569395694
exception Error of Location.t * Env.t * error
9569495695
exception Error_forward of Location.error
9569595696

@@ -95798,6 +95799,7 @@ type error =
9579895799
| Labels_omitted of string list
9579995800
| Empty_record_literal
9580095801
| Uncurried_arity_mismatch of type_expr * int * int
95802+
| Field_not_optional of string * type_expr
9580195803
exception Error of Location.t * Env.t * error
9580295804
exception Error_forward of Location.error
9580395805

@@ -96033,6 +96035,19 @@ let extract_concrete_variant env ty =
9603396035
| (p0, p, {type_kind=Type_open}) -> (p0, p, [])
9603496036
| _ -> raise Not_found
9603596037

96038+
let label_is_optional ld =
96039+
match ld.lbl_repres with
96040+
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
96041+
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
96042+
| _ -> false
96043+
96044+
let check_optional_attr env ld attrs loc =
96045+
let check_redundant () =
96046+
if not (label_is_optional ld) then
96047+
raise (Error (loc, env, Field_not_optional (ld.lbl_name, ld.lbl_res)));
96048+
true in
96049+
Ext_list.exists attrs (fun ({txt}, _) ->
96050+
txt = "ns.optional" && check_redundant ())
9603696051

9603796052
(* unification inside type_pat*)
9603896053
let unify_pat_types loc env ty ty' =
@@ -96875,15 +96890,8 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
9687596890
Some (p0, p), expected_ty
9687696891
with Not_found -> None, newvar ()
9687796892
in
96878-
let label_is_optional ld =
96879-
match ld.lbl_repres with
96880-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
96881-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
96882-
| _ -> false in
9688396893
let process_optional_label (ld, pat) =
96884-
let exp_optional_attr =
96885-
Ext_list.exists pat.ppat_attributes (fun ({txt },_) -> txt = "ns.optional")
96886-
in
96894+
let exp_optional_attr = check_optional_attr !env ld pat.ppat_attributes pat.ppat_loc in
9688796895
let isFromPamatch = match pat.ppat_desc with
9688896896
| Ppat_construct ({txt = Lident s}, _) ->
9688996897
String.length s >= 2 && s.[0] = '#' && s.[1] = '$'
@@ -97602,15 +97610,8 @@ and type_expect_ ?in_function ?(recarg=Rejected) env sexp ty_expected =
9760297610
unify_exp env (re exp) (instance env ty_expected);
9760397611
exp
9760497612
in
97605-
let label_is_optional ld =
97606-
match ld.lbl_repres with
97607-
| Record_optional_labels lbls -> Ext_list.mem_string lbls ld.lbl_name
97608-
| Record_inlined {optional_labels} -> Ext_list.mem_string optional_labels ld.lbl_name
97609-
| _ -> false in
9761097613
let process_optional_label (id, ld, e) =
97611-
let exp_optional_attr =
97612-
Ext_list.exists e.pexp_attributes (fun ({txt },_) -> txt = "ns.optional")
97613-
in
97614+
let exp_optional_attr = check_optional_attr env ld e.pexp_attributes e.pexp_loc in
9761497615
if label_is_optional ld && not exp_optional_attr then
9761597616
let lid = mknoloc (Longident.(Ldot (Lident "*predef*", "Some"))) in
9761697617
let e = Ast_helper.Exp.construct ~loc:e.pexp_loc lid (Some e)
@@ -99600,6 +99601,11 @@ let report_error env ppf = function
9960099601
type_expr typ;
9960199602
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
9960299603
args (if args = 0 then "" else "s") arity
99604+
| Field_not_optional (name, typ) ->
99605+
fprintf ppf
99606+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
99607+
type_expr typ
99608+
9960399609

9960499610
let super_report_error_no_wrap_printing_env = report_error
9960599611

0 commit comments

Comments
 (0)