@@ -35,8 +35,8 @@ type error =
35
35
| Expr_type_clash of (type_expr * type_expr ) list * (type_clash_context option )
36
36
| Apply_non_function of type_expr
37
37
| Apply_wrong_label of arg_label * type_expr
38
- | Label_multiply_defined of string
39
- | Labels_missing of string list * bool
38
+ | Label_multiply_defined of { label : string ; jsx_component_info : jsx_prop_error_info option }
39
+ | Labels_missing of { labels : string list ; jsx_component_info : jsx_prop_error_info option }
40
40
| Label_not_mutable of Longident .t
41
41
| Wrong_name of string * type_expr * string * Path .t * string * string list
42
42
| Name_type_mismatch of
@@ -960,15 +960,18 @@ let type_label_a_list ?labels loc closed env type_lbl_a opath lid_a_list k =
960
960
(* Checks over the labels mentioned in a record pattern:
961
961
no duplicate definitions (error); properly closed (warning) *)
962
962
963
- let check_recordpat_labels loc lbl_pat_list closed =
963
+ let check_recordpat_labels ~ get_jsx_component_error_info loc lbl_pat_list closed =
964
964
match lbl_pat_list with
965
965
| [] -> () (* should not happen *)
966
- | (_ , label1 , _ ) :: _ ->
966
+ | (( l : Longident.t loc ) , label1 , _ ) :: _ ->
967
967
let all = label1.lbl_all in
968
968
let defined = Array. make (Array. length all) false in
969
969
let check_defined (_ , label , _ ) =
970
970
if defined.(label.lbl_pos)
971
- then raise(Error (loc, Env. empty, Label_multiply_defined label.lbl_name))
971
+ then raise(Error (l.loc, Env. empty, Label_multiply_defined {
972
+ label = label.lbl_name;
973
+ jsx_component_info = get_jsx_component_error_info () ;
974
+ }))
972
975
else defined.(label.lbl_pos) < - true in
973
976
List. iter check_defined lbl_pat_list;
974
977
if closed = Closed
@@ -1292,6 +1295,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
1292
1295
Some (p0, p), expected_ty
1293
1296
with Not_found -> None , newvar ()
1294
1297
in
1298
+ let get_jsx_component_error_info = get_jsx_component_error_info ~extract_concrete_typedecl opath ! env record_ty in
1295
1299
let process_optional_label (ld , pat ) =
1296
1300
let exp_optional_attr = check_optional_attr ! env ld pat.ppat_attributes pat.ppat_loc in
1297
1301
let is_from_pamatch = match pat.ppat_desc with
@@ -1330,7 +1334,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
1330
1334
k (label_lid, label, arg))
1331
1335
in
1332
1336
let k' k lbl_pat_list =
1333
- check_recordpat_labels loc lbl_pat_list closed;
1337
+ check_recordpat_labels ~get_jsx_component_error_info loc lbl_pat_list closed;
1334
1338
unify_pat_types loc ! env record_ty expected_ty;
1335
1339
rp k {
1336
1340
pat_desc = Tpat_record (lbl_pat_list, closed);
@@ -1897,11 +1901,14 @@ let duplicate_ident_types caselist env =
1897
1901
(* type_label_a_list returns a list of labels sorted by lbl_pos *)
1898
1902
(* note: check_duplicates would better be implemented in
1899
1903
type_label_a_list directly *)
1900
- let rec check_duplicates loc env = function
1901
- | (_ , lbl1 , _ ) :: (_ , lbl2 , _ ) :: _ when lbl1.lbl_pos = lbl2.lbl_pos ->
1902
- raise(Error (loc, env, Label_multiply_defined lbl1.lbl_name))
1904
+ let rec check_duplicates ~get_jsx_component_error_info loc env = function
1905
+ | (_ , lbl1 , _ ) :: ((l : Longident.t loc ), lbl2 , _ ) :: _ when lbl1.lbl_pos = lbl2.lbl_pos ->
1906
+ raise(Error (l.loc, env, Label_multiply_defined {
1907
+ label = lbl1.lbl_name;
1908
+ jsx_component_info = get_jsx_component_error_info() ;
1909
+ }))
1903
1910
| _ :: rem ->
1904
- check_duplicates loc env rem
1911
+ check_duplicates ~get_jsx_component_error_info loc env rem
1905
1912
| [] -> ()
1906
1913
(* Getting proper location of already typed expressions.
1907
1914
@@ -1974,11 +1981,6 @@ let rec lower_args env seen ty_fun =
1974
1981
let not_function env ty =
1975
1982
let ls, tvar = list_labels env ty in
1976
1983
ls = [] && not tvar
1977
-
1978
- let check_might_be_component env ty_record =
1979
- match (expand_head env ty_record).desc with
1980
- | Tconstr (path , _ , _ ) when path |> Path. last = " props" -> true
1981
- | _ -> false
1982
1984
1983
1985
type lazy_args =
1984
1986
(Asttypes .arg_label * (unit -> Typedtree .expression ) option ) list
@@ -2279,6 +2281,10 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2279
2281
| exception Not_found ->
2280
2282
newvar () , None , [] , None
2281
2283
2284
+ in
2285
+ let get_jsx_component_error_info () = (match opath with
2286
+ | Some (p , _ ) -> get_jsx_component_props ~extract_concrete_typedecl env ty_record p
2287
+ | None -> None )
2282
2288
in
2283
2289
let lbl_exp_list =
2284
2290
wrap_disambiguate " This record expression is expected to have" ty_record
@@ -2288,7 +2294,7 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2288
2294
(fun x -> x)
2289
2295
in
2290
2296
unify_exp_types loc env ty_record (instance env ty_expected);
2291
- check_duplicates loc env lbl_exp_list;
2297
+ check_duplicates ~get_jsx_component_error_info loc env lbl_exp_list;
2292
2298
let label_descriptions, representation = match lbl_exp_list, repr_opt with
2293
2299
| (_ , { lbl_all = label_descriptions ; lbl_repres = representation } , _ ) :: _ , _ -> label_descriptions, representation
2294
2300
| [] , Some (representation ) when lid_sexp_list = [] ->
@@ -2304,8 +2310,10 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2304
2310
Some name in
2305
2311
let labels_missing = fields |> List. filter_map filter_missing in
2306
2312
if labels_missing <> [] then (
2307
- let might_be_component = check_might_be_component env ty_record in
2308
- raise(Error (loc, env, Labels_missing (labels_missing, might_be_component))));
2313
+ raise(Error (loc, env, Labels_missing {
2314
+ labels = labels_missing;
2315
+ jsx_component_info = get_jsx_component_error_info () ;
2316
+ })));
2309
2317
[||], representation
2310
2318
| [] , _ ->
2311
2319
if fields = [] && repr_opt <> None then
@@ -2330,8 +2338,10 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2330
2338
label_descriptions
2331
2339
in
2332
2340
if ! labels_missing <> [] then (
2333
- let might_be_component = check_might_be_component env ty_record in
2334
- raise(Error (loc, env, Labels_missing ((List. rev ! labels_missing), might_be_component))));
2341
+ raise(Error (loc, env, Labels_missing {
2342
+ labels= (List. rev ! labels_missing);
2343
+ jsx_component_info = get_jsx_component_error_info () ;
2344
+ })));
2335
2345
let fields =
2336
2346
Array. map2 (fun descr def -> descr, def)
2337
2347
label_descriptions label_definitions
@@ -2372,6 +2382,7 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2372
2382
end
2373
2383
| op -> ty_expected, op
2374
2384
in
2385
+ let get_jsx_component_error_info = get_jsx_component_error_info ~extract_concrete_typedecl opath env ty_record in
2375
2386
let closed = false in
2376
2387
let lbl_exp_list =
2377
2388
wrap_disambiguate " This record expression is expected to have" ty_record
@@ -2381,7 +2392,7 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
2381
2392
(fun x -> x)
2382
2393
in
2383
2394
unify_exp_types loc env ty_record (instance env ty_expected);
2384
- check_duplicates loc env lbl_exp_list;
2395
+ check_duplicates ~get_jsx_component_error_info loc env lbl_exp_list;
2385
2396
let opt_exp, label_definitions =
2386
2397
let (_lid, lbl, _lbl_exp) = List. hd lbl_exp_list in
2387
2398
let matching_label lbl =
@@ -3846,17 +3857,25 @@ let report_error env ppf = function
3846
3857
" @[<v>@[<2>The function applied to this argument has type@ %a@]@.\
3847
3858
This argument cannot be applied %a@]"
3848
3859
type_expr ty print_label l
3849
- | Label_multiply_defined s ->
3850
- fprintf ppf " The record field label %s is defined several times" s
3851
- | Labels_missing (labels , might_be_component ) ->
3860
+ | Label_multiply_defined {label; jsx_component_info = Some jsx_component_info } ->
3861
+ fprintf ppf " The prop @{<info>%s@} has already been passed to the component " label;
3862
+ print_component_name ppf jsx_component_info.props_record_path;
3863
+ fprintf ppf " @,@,You can't pass the same prop more than once." ;
3864
+ | Label_multiply_defined {label} ->
3865
+ fprintf ppf " The record field label %s is defined several times" label
3866
+ | Labels_missing {labels; jsx_component_info = Some jsx_component_info } ->
3867
+ print_component_labels_missing_error ppf labels jsx_component_info
3868
+ | Labels_missing {labels} ->
3852
3869
let print_labels ppf =
3853
3870
List. iter (fun lbl -> fprintf ppf " @ %s" ( lbl)) in
3854
- let component_text = if might_be_component then " If this is a component, add the missing props." else " " in
3855
- fprintf ppf " @[<hov>Some required record fields are missing:%a.%s@]"
3856
- print_labels labels component_text
3871
+ fprintf ppf " @[<hov>Some required record fields are missing:%a.@]"
3872
+ print_labels labels
3857
3873
| Label_not_mutable lid ->
3858
3874
fprintf ppf " The record field %a is not mutable" longident lid
3859
3875
| Wrong_name (eorp , ty , kind , p , name , valid_names ) ->
3876
+ (match get_jsx_component_props ~extract_concrete_typedecl env ty p with
3877
+ | Some {fields} -> print_component_wrong_prop_error ppf p fields name; spellcheck ppf name valid_names;
3878
+ | None ->
3860
3879
(* modified *)
3861
3880
if Path. is_constructor_typath p then begin
3862
3881
fprintf ppf " @[The field %s is not part of the record \
@@ -3876,6 +3895,7 @@ let report_error env ppf = function
3876
3895
fprintf ppf " @]" ;
3877
3896
end ;
3878
3897
spellcheck ppf name valid_names;
3898
+ )
3879
3899
| Name_type_mismatch (kind , lid , tp , tpl ) ->
3880
3900
let name = label_of_kind kind in
3881
3901
report_ambiguous_type_error ppf env tp tpl
0 commit comments