@@ -35,8 +35,8 @@ type error =
3535 | Expr_type_clash of (type_expr * type_expr ) list * (type_clash_context option )
3636 | Apply_non_function of type_expr
3737 | 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 }
4040 | Label_not_mutable of Longident .t
4141 | Wrong_name of string * type_expr * string * Path .t * string * string list
4242 | 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 =
960960(* Checks over the labels mentioned in a record pattern:
961961 no duplicate definitions (error); properly closed (warning) *)
962962
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 =
964964 match lbl_pat_list with
965965 | [] -> () (* should not happen *)
966- | (_ , label1 , _ ) :: _ ->
966+ | (( l : Longident.t loc ) , label1 , _ ) :: _ ->
967967 let all = label1.lbl_all in
968968 let defined = Array. make (Array. length all) false in
969969 let check_defined (_ , label , _ ) =
970970 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+ }))
972975 else defined.(label.lbl_pos) < - true in
973976 List. iter check_defined lbl_pat_list;
974977 if closed = Closed
@@ -1292,6 +1295,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
12921295 Some (p0, p), expected_ty
12931296 with Not_found -> None , newvar ()
12941297 in
1298+ let get_jsx_component_error_info = get_jsx_component_error_info ~extract_concrete_typedecl opath ! env record_ty in
12951299 let process_optional_label (ld , pat ) =
12961300 let exp_optional_attr = check_optional_attr ! env ld pat.ppat_attributes pat.ppat_loc in
12971301 let is_from_pamatch = match pat.ppat_desc with
@@ -1330,7 +1334,7 @@ and type_pat_aux ~constrs ~labels ~no_existentials ~mode ~explode ~env
13301334 k (label_lid, label, arg))
13311335 in
13321336 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;
13341338 unify_pat_types loc ! env record_ty expected_ty;
13351339 rp k {
13361340 pat_desc = Tpat_record (lbl_pat_list, closed);
@@ -1897,11 +1901,14 @@ let duplicate_ident_types caselist env =
18971901(* type_label_a_list returns a list of labels sorted by lbl_pos *)
18981902(* note: check_duplicates would better be implemented in
18991903 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+ }))
19031910 | _ :: rem ->
1904- check_duplicates loc env rem
1911+ check_duplicates ~get_jsx_component_error_info loc env rem
19051912 | [] -> ()
19061913(* Getting proper location of already typed expressions.
19071914
@@ -1974,11 +1981,6 @@ let rec lower_args env seen ty_fun =
19741981let not_function env ty =
19751982 let ls, tvar = list_labels env ty in
19761983 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
19821984
19831985type lazy_args =
19841986 (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
22792281 | exception Not_found ->
22802282 newvar () , None , [] , None
22812283
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 )
22822288 in
22832289 let lbl_exp_list =
22842290 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
22882294 (fun x -> x)
22892295 in
22902296 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;
22922298 let label_descriptions, representation = match lbl_exp_list, repr_opt with
22932299 | (_ , { lbl_all = label_descriptions ; lbl_repres = representation } , _ ) :: _ , _ -> label_descriptions, representation
22942300 | [] , Some (representation ) when lid_sexp_list = [] ->
@@ -2304,8 +2310,10 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
23042310 Some name in
23052311 let labels_missing = fields |> List. filter_map filter_missing in
23062312 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+ })));
23092317 [||], representation
23102318 | [] , _ ->
23112319 if fields = [] && repr_opt <> None then
@@ -2330,8 +2338,10 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
23302338 label_descriptions
23312339 in
23322340 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+ })));
23352345 let fields =
23362346 Array. map2 (fun descr def -> descr, def)
23372347 label_descriptions label_definitions
@@ -2372,6 +2382,7 @@ and type_expect_ ?type_clash_context ?in_function ?(recarg=Rejected) env sexp ty
23722382 end
23732383 | op -> ty_expected, op
23742384 in
2385+ let get_jsx_component_error_info = get_jsx_component_error_info ~extract_concrete_typedecl opath env ty_record in
23752386 let closed = false in
23762387 let lbl_exp_list =
23772388 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
23812392 (fun x -> x)
23822393 in
23832394 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;
23852396 let opt_exp, label_definitions =
23862397 let (_lid, lbl, _lbl_exp) = List. hd lbl_exp_list in
23872398 let matching_label lbl =
@@ -3846,17 +3857,25 @@ let report_error env ppf = function
38463857 " @[<v>@[<2>The function applied to this argument has type@ %a@]@.\
38473858 This argument cannot be applied %a@]"
38483859 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} ->
38523869 let print_labels ppf =
38533870 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
38573873 | Label_not_mutable lid ->
38583874 fprintf ppf " The record field %a is not mutable" longident lid
38593875 | 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 ->
38603879 (* modified *)
38613880 if Path. is_constructor_typath p then begin
38623881 fprintf ppf " @[The field %s is not part of the record \
@@ -3876,6 +3895,7 @@ let report_error env ppf = function
38763895 fprintf ppf " @]" ;
38773896 end ;
38783897 spellcheck ppf name valid_names;
3898+ )
38793899 | Name_type_mismatch (kind , lid , tp , tpl ) ->
38803900 let name = label_of_kind kind in
38813901 report_ambiguous_type_error ppf env tp tpl
0 commit comments