@@ -43,7 +43,7 @@ type error =
43
43
| Method_mismatch of string * type_expr * type_expr
44
44
| Unbound_value of Longident .t
45
45
| Unbound_constructor of Longident .t
46
- | Unbound_label of Longident .t
46
+ | Unbound_label of Longident .t * type_expr option
47
47
| Unbound_module of Longident .t
48
48
| Unbound_modtype of Longident .t
49
49
| Ill_typed_functor_application of Longident .t
@@ -129,7 +129,7 @@ let find_all_constructors =
129
129
find_component Env. lookup_all_constructors (fun lid ->
130
130
Unbound_constructor lid)
131
131
let find_all_labels =
132
- find_component Env. lookup_all_labels (fun lid -> Unbound_label lid)
132
+ find_component Env. lookup_all_labels (fun lid -> Unbound_label ( lid, None ) )
133
133
134
134
let find_value env loc lid =
135
135
Env. check_value_name (Longident. last lid) loc;
@@ -160,12 +160,14 @@ let find_modtype env loc lid =
160
160
Builtin_attributes. check_deprecated loc decl.mtd_attributes (Path. name path);
161
161
r
162
162
163
- let unbound_constructor_error env lid =
163
+ let unbound_constructor_error ?from_type env lid =
164
+ ignore from_type;
164
165
narrow_unbound_lid_error env lid.loc lid.txt (fun lid ->
165
166
Unbound_constructor lid)
166
167
167
- let unbound_label_error env lid =
168
- narrow_unbound_lid_error env lid.loc lid.txt (fun lid -> Unbound_label lid)
168
+ let unbound_label_error ?from_type env lid =
169
+ narrow_unbound_lid_error env lid.loc lid.txt (fun lid ->
170
+ Unbound_label (lid, from_type))
169
171
170
172
(* Support for first-class modules. *)
171
173
@@ -909,18 +911,49 @@ let report_error env ppf = function
909
911
= Bar@}.@]@]"
910
912
Printtyp. longident lid Printtyp. longident lid Printtyp. longident lid;
911
913
spellcheck ppf fold_constructors env lid
912
- | Unbound_label lid ->
914
+ | Unbound_label ( lid , from_type ) ->
913
915
(* modified *)
914
- Format. fprintf ppf
915
- " @[<v>@{<info>%a@} refers to a record field, but no corresponding record \
916
- type is in scope.@,\
917
- @,\
918
- If it's defined in another module or file, bring it into scope by:@,\
919
- @[- Prefixing the field name with the module name:@ \
920
- @{<info>TheModule.%a@}@]@,\
921
- @[- Or specifying the record type explicitly:@ @{<info>let theValue: \
922
- TheModule.theType = {%a: VALUE}@}@]@]"
923
- Printtyp. longident lid Printtyp. longident lid Printtyp. longident lid;
916
+ (match from_type with
917
+ | Some {desc = Tconstr (p , _ , _ )} when Path. same p Predef. path_option ->
918
+ (* TODO: Extend for nullable/null? *)
919
+ Format. fprintf ppf
920
+ " @[<v>You're trying to access the record field @{<info>%a@}, but the \
921
+ thing you're trying to access it on is an @{<info>option@}.@ You need \
922
+ to unwrap the option first before accessing the record field.@,\
923
+ @\n \
924
+ Possible solutions:@,\
925
+ @[- Use @{<info>Option.map@} to transform the option: \
926
+ @{<info>xx->Option.map(field => field.%a)@}@]@,\
927
+ @[- Or use @{<info>Option.getOr@} with a default: \
928
+ @{<info>xx->Option.getOr(defaultRecord).%a@}@]@]"
929
+ Printtyp. longident lid Printtyp. longident lid Printtyp. longident lid
930
+ | Some {desc = Tconstr (p , _ , _ )} when Path. same p Predef. path_array ->
931
+ Format. fprintf ppf
932
+ " @[<v>You're trying to access the record field @{<info>%a@}, but the \
933
+ thing you're trying to access it on is an @{<info>array@}.@ You need \
934
+ to access an individual element of the array if you want to access an \
935
+ individual record field.@]"
936
+ Printtyp. longident lid
937
+ | Some ({desc = Tconstr (_p , _ , _ )} as t1 ) ->
938
+ Format. fprintf ppf
939
+ " @[<v>You're trying to access the record field @{<info>%a@}, but the \
940
+ thing you're trying to access it on is not a record. @,\n \
941
+ The type of the thing you're trying to access it on is:@,\n \
942
+ %a@,\n \
943
+ @,\
944
+ Only records have fields that can be accessed with dot notation.@]"
945
+ Printtyp. longident lid Error_message_utils. type_expr t1
946
+ | None | Some _ ->
947
+ Format. fprintf ppf
948
+ " @[<v>@{<info>%a@} refers to a record field, but no corresponding \
949
+ record type is in scope.@,\
950
+ @,\
951
+ If it's defined in another module or file, bring it into scope by:@,\
952
+ @[- Prefixing the field name with the module name:@ \
953
+ @{<info>TheModule.%a@}@]@,\
954
+ @[- Or specifying the record type explicitly:@ @{<info>let theValue: \
955
+ TheModule.theType = {%a: VALUE}@}@]@]"
956
+ Printtyp. longident lid Printtyp. longident lid Printtyp. longident lid);
924
957
spellcheck ppf fold_labels env lid
925
958
| Unbound_modtype lid ->
926
959
fprintf ppf " Unbound module type %a" longident lid;
0 commit comments