Skip to content

Commit 5678f62

Browse files
committed
Better handling of errors in 'type_of.ml'
The code for 'module type of' expansion runs before any other resolution happens, and it needs to run until a fixed point. Since the change to use 'Result.t' over simply raising exceptions when we notice we'll need to recurse, a bug was introduced when the specific error case we're looking for was swallowed in another layer. This PR attempts to make sure we don't ever throw away an error raised during signature expansion and adds some code to check in the combined error whether the root cause was in fact the case we're looking for; `` `UnexpandedTypeOf `` in this case. Signed-off-by: Jon Ludlam <jon@recoil.org>
1 parent 8b0a632 commit 5678f62

File tree

4 files changed

+72
-45
lines changed

4 files changed

+72
-45
lines changed

src/xref2/errors.ml

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ module Tools_error = struct
1313
| `UnresolvedForwardPath
1414
(** The module signature depends upon a forward path *)
1515
| `UnresolvedPath of
16-
[ `Module of Cpath.module_ | `ModuleType of Cpath.module_type ]
16+
[ `Module of Cpath.module_ * simple_module_lookup_error
17+
| `ModuleType of Cpath.module_type * simple_module_type_lookup_error ]
1718
(** The path to the module or module type could not be resolved *)
1819
| `UnexpandedTypeOf of Component.ModuleType.type_of_desc
1920
(** The `module type of` expression could not be expanded *) ]
2021

21-
type simple_module_lookup_error =
22+
and simple_module_lookup_error =
2223
[ `Local of Env.t * Ident.path_module
2324
(** Internal error: Found local path during lookup *)
2425
| `Unresolved_apply (** [`Apply] argument is not [`Resolved] *)
@@ -37,7 +38,8 @@ module Tools_error = struct
3738
| `UnresolvedForwardPath
3839
(** The module signature depends upon a forward path *)
3940
| `UnresolvedPath of
40-
[ `Module of Cpath.module_ | `ModuleType of Cpath.module_type ]
41+
[ `Module of Cpath.module_ * simple_module_lookup_error
42+
| `ModuleType of Cpath.module_type * simple_module_type_lookup_error ]
4143
| `Parent of parent_lookup_error ]
4244

4345
and simple_module_type_lookup_error =
@@ -77,19 +79,20 @@ module Tools_error = struct
7779
| simple_module_type_lookup_error
7880
| simple_module_type_expr_of_module_error
7981
| simple_module_lookup_error
80-
| signature_of_module_error ]
82+
| signature_of_module_error
83+
| parent_lookup_error ]
8184

8285
let rec pp : Format.formatter -> any -> unit =
8386
fun fmt err ->
8487
match err with
8588
| `OpaqueModule -> Format.fprintf fmt "OpaqueModule"
8689
| `UnresolvedForwardPath -> Format.fprintf fmt "Unresolved forward path"
87-
| `UnresolvedPath (`Module p) ->
88-
Format.fprintf fmt "Unresolved module path %a" Component.Fmt.module_path
89-
p
90-
| `UnresolvedPath (`ModuleType p) ->
91-
Format.fprintf fmt "Unresolved module type path %a"
92-
Component.Fmt.module_type_path p
90+
| `UnresolvedPath (`Module (p, e)) ->
91+
Format.fprintf fmt "Unresolved module path %a (%a)" Component.Fmt.module_path
92+
p pp (e :> any)
93+
| `UnresolvedPath (`ModuleType (p, e)) ->
94+
Format.fprintf fmt "Unresolved module type path %a (%a)"
95+
Component.Fmt.module_type_path p pp (e :> any)
9396
| `LocalMT (_, id) -> Format.fprintf fmt "Local id found: %a" Ident.fmt id
9497
| `Local (_, id) -> Format.fprintf fmt "Local id found: %a" Ident.fmt id
9598
| `LocalType (_, id) -> Format.fprintf fmt "Local id found: %a" Ident.fmt id
@@ -111,16 +114,10 @@ module Tools_error = struct
111114
(m :> Odoc_model.Paths.Identifier.t)
112115
| `ApplyNotFunctor -> Format.fprintf fmt "Apply module is not a functor"
113116
| `Class_replaced -> Format.fprintf fmt "Class replaced"
114-
| `Parent p -> pp_parent fmt p
117+
| `Parent p -> pp fmt (p :> any)
115118
| `UnexpandedTypeOf t ->
116119
Format.fprintf fmt "Unexpanded `module type of` expression: %a"
117120
Component.Fmt.module_type_type_of_desc t
118-
119-
120-
and pp_parent : Format.formatter -> parent_lookup_error -> unit =
121-
fun fmt err ->
122-
match err with
123-
| `Parent p -> pp_parent fmt p
124121
| `Parent_sig e -> Format.fprintf fmt "Parent_sig: %a" pp (e :> any)
125122
| `Parent_module_type e ->
126123
Format.fprintf fmt "Parent_module_type: %a" pp (e :> any)
@@ -129,6 +126,35 @@ module Tools_error = struct
129126
| `Fragment_root -> Format.fprintf fmt "Fragment root"
130127
end
131128

129+
(* Ugh. we need to determine whether this was down to an unexpanded module type error. This is horrendous. *)
130+
let is_unexpanded_module_type_of =
131+
let open Tools_error in
132+
let rec inner : any -> bool = function
133+
| `Local _ -> false
134+
| `Find_failure -> false
135+
| `Lookup_failure _ -> false
136+
| `Unresolved_apply -> false
137+
| `Lookup_failure_root _ -> false
138+
| `Parent p -> inner (p :> any)
139+
| `Parent_sig p -> inner (p :> any)
140+
| `Parent_module_type p -> inner (p :> any)
141+
| `Parent_expr p -> inner (p :> any)
142+
| `Parent_module p -> inner (p :> any)
143+
| `Fragment_root -> false
144+
| `OpaqueModule -> false
145+
| `UnresolvedForwardPath -> false
146+
| `UnexpandedTypeOf _ -> true (* woo *)
147+
| `LocalMT _ -> false
148+
| `Lookup_failureMT _ -> false
149+
| `ApplyNotFunctor -> false
150+
| `UnresolvedPath (`Module (_, e)) -> inner (e :> any)
151+
| `UnresolvedPath (`ModuleType (_, e)) -> inner (e :> any)
152+
| `Lookup_failureT _ -> false
153+
| `LocalType _ -> false
154+
| `Class_replaced -> false
155+
in inner
156+
157+
132158
(** To use as [Lookup_failures.kind]. *)
133159
let rec kind_of_module_cpath = function
134160
| `Root _ -> Some `Root
@@ -145,8 +171,8 @@ let rec kind_of_module_type_cpath = function
145171
| _ -> None
146172

147173
let rec kind_of_error = function
148-
| `UnresolvedPath (`Module cp) -> kind_of_module_cpath cp
149-
| `UnresolvedPath (`ModuleType cp) -> kind_of_module_type_cpath cp
174+
| `UnresolvedPath (`Module (cp, _)) -> kind_of_module_cpath cp
175+
| `UnresolvedPath (`ModuleType (cp, _)) -> kind_of_module_type_cpath cp
150176
| `Lookup_failure (`Root _) | `Lookup_failure_root _ -> Some `Root
151177
| `Parent (`Parent_sig e) -> kind_of_error (e :> Tools_error.any)
152178
| `Parent (`Parent_module_type e) -> kind_of_error (e :> Tools_error.any)

src/xref2/expand_tools.ml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ and aux_expansion_of_module_alias env ~strengthen path =
8383
Component.Fmt.signature sg'; *)
8484
Ok (Signature { sg' with items = Comment (`Docs docs) :: sg'.items })
8585
| Ok (Functor _ as x), _ -> Ok x )
86-
| Error _ -> Error (`UnresolvedPath (`Module path))
86+
| Error e ->
87+
Error (`UnresolvedPath (`Module (path, e)))
8788

8889
(* We need to reresolve fragments in expansions as the root of the fragment
8990
may well change - so we turn resolved fragments back into unresolved ones
@@ -114,7 +115,7 @@ and aux_expansion_of_u_module_type_expr env expr :
114115
match expr with
115116
| Component.ModuleType.U.Path p ->
116117
Tools.resolve_module_type ~mark_substituted:false env p
117-
|> map_error (fun _ -> (`UnresolvedPath (`ModuleType p) : signature_of_module_error))
118+
|> map_error (fun e -> (`UnresolvedPath (`ModuleType (p, e)) : signature_of_module_error))
118119
>>= fun (_, mt) -> aux_expansion_of_module_type env mt
119120
>>= assert_not_functor
120121
| Signature sg -> Ok (sg)
@@ -131,7 +132,7 @@ and aux_expansion_of_module_type_expr env expr :
131132
match expr with
132133
| Path {p_path; _} ->
133134
Tools.resolve_module_type ~mark_substituted:false env p_path
134-
|> map_error (fun _ -> (`UnresolvedPath (`ModuleType p_path) : signature_of_module_error))
135+
|> map_error (fun e -> (`UnresolvedPath (`ModuleType (p_path, e)) : signature_of_module_error))
135136
>>= fun (_, mt) -> aux_expansion_of_module_type env mt
136137
| Signature s -> Ok (Signature s)
137138
| With {w_substitutions; w_expr; _} -> (

src/xref2/tools.ml

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -404,10 +404,9 @@ and handle_module_lookup env ~add_canonical id parent sg sub =
404404
let m' = Subst.module_ sub m in
405405
let md' = Component.Delayed.put_val m' in
406406
Ok (process_module_path env ~add_canonical m' p', md')
407-
| Some (`FModule_removed p) -> (
408-
match lookup_module ~mark_substituted:false env p with
409-
| Ok m -> Ok (p, m)
410-
| Error _ as e -> e )
407+
| Some (`FModule_removed p) ->
408+
lookup_module ~mark_substituted:false env p
409+
>>= fun m -> Ok (p, m)
411410
| None -> Error `Find_failure
412411

413412
and handle_module_type_lookup env id p sg sub =
@@ -447,15 +446,14 @@ and lookup_module :
447446
of_option ~error:(`Lookup_failure i) (Env.(lookup_by_id s_module) i env)
448447
>>= fun (`Module (_, m)) -> Ok m
449448
| `Substituted x -> lookup_module ~mark_substituted env x
450-
| `Apply (functor_path, argument_path) -> (
451-
match lookup_module ~mark_substituted env functor_path with
452-
| Ok functor_module ->
453-
let functor_module = Component.Delayed.get functor_module in
454-
handle_apply ~mark_substituted:false env functor_path argument_path
455-
functor_module
456-
|> map_error (fun e -> `Parent (`Parent_expr e))
457-
>>= fun (_, m) -> Ok (Component.Delayed.put_val m)
458-
| Error _ as e -> e )
449+
| `Apply (functor_path, argument_path) ->
450+
lookup_module ~mark_substituted env functor_path
451+
>>= fun functor_module ->
452+
let functor_module = Component.Delayed.get functor_module in
453+
handle_apply ~mark_substituted:false env functor_path argument_path
454+
functor_module
455+
|> map_error (fun e -> `Parent (`Parent_expr e))
456+
>>= fun (_, m) -> Ok (Component.Delayed.put_val m)
459457
| `Module (parent, name) ->
460458
let find_in_sg sg sub =
461459
match Find.careful_module_in_sig sg (ModuleName.to_string name) with
@@ -958,7 +956,7 @@ and module_type_expr_of_module_decl :
958956
module_type_expr_of_module env m
959957
| Error _ when Cpath.is_module_forward path ->
960958
Error `UnresolvedForwardPath
961-
| Error _ -> Error (`UnresolvedPath (`Module path)) )
959+
| Error e -> Error (`UnresolvedPath (`Module (path, e))) )
962960
| Component.Module.ModuleType expr -> Ok expr
963961

964962
and module_type_expr_of_module :
@@ -982,7 +980,7 @@ and signature_of_module_path :
982980
signature_of_module_cached env p' m >>= fun sg ->
983981
if strengthen then Ok (Strengthen.signature (`Resolved p') sg) else Ok sg
984982
| Error _ when Cpath.is_module_forward path -> Error `UnresolvedForwardPath
985-
| Error _ -> Error (`UnresolvedPath (`Module path))
983+
| Error e -> Error (`UnresolvedPath (`Module (path, e)))
986984

987985
and handle_signature_with_subs :
988986
mark_substituted:bool ->
@@ -1007,7 +1005,7 @@ and signature_of_u_module_type_expr :
10071005
| Component.ModuleType.U.Path p -> (
10081006
match resolve_module_type ~mark_substituted env p with
10091007
| Ok (_, mt) -> signature_of_module_type env mt
1010-
| Error _ -> Error (`UnresolvedPath (`ModuleType p)) )
1008+
| Error e -> Error (`UnresolvedPath (`ModuleType (p, e))) )
10111009
| Signature s -> Ok s
10121010
| With (subs, s) ->
10131011
signature_of_u_module_type_expr ~mark_substituted env s >>= fun sg ->
@@ -1032,7 +1030,7 @@ and signature_of_module_type_expr :
10321030
| Component.ModuleType.Path {p_path; _} -> (
10331031
match resolve_module_type ~mark_substituted env p_path with
10341032
| Ok (_, mt) -> signature_of_module_type env mt
1035-
| Error _ -> Error (`UnresolvedPath (`ModuleType p_path)) )
1033+
| Error e -> Error (`UnresolvedPath (`ModuleType (p_path, e))) )
10361034
| Component.ModuleType.Signature s -> Ok s
10371035
| Component.ModuleType.With {w_expansion=Some e; _} ->
10381036
Ok (signature_of_simple_expansion e)
@@ -1227,10 +1225,10 @@ and fragmap :
12271225
resolve_module ~mark_substituted ~add_canonical:false env p
12281226
with
12291227
| Ok (p, _) -> Ok (Right p)
1230-
| Error _ ->
1228+
| Error e ->
12311229
Format.fprintf Format.err_formatter
12321230
"failed to resolve path: %a\n%!" Component.Fmt.module_path p;
1233-
Error (`UnresolvedPath (`Module p))
1231+
Error (`UnresolvedPath (`Module (p, e)))
12341232
in
12351233
map_signature None (Some (name, mapfn)) sg.items )
12361234
| TypeEq (frag, equation) -> (

src/xref2/type_of.ml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ and module_type_expr env (id : Id.Signature.t) expr =
6161
| TypeOf t ->
6262
match module_type_expr_typeof env id t with
6363
| Ok e -> TypeOf {t with t_expansion = Some (Lang_of.(simple_expansion empty id e)) }
64-
| Error (`UnexpandedTypeOf _) -> again := true; expr
65-
| Error _ -> expr
64+
| Error e when Errors.is_unexpanded_module_type_of (e :> Errors.Tools_error.any) -> again := true; expr
65+
| Error _e ->
66+
expr
6667

6768
and u_module_type_expr env id expr =
6869
match expr with
@@ -72,8 +73,9 @@ and u_module_type_expr env id expr =
7273
| TypeOf t ->
7374
match module_type_expr_typeof env id t with
7475
| Ok e -> TypeOf {t with t_expansion = Some (Lang_of.(simple_expansion empty id e)) }
75-
| Error (`UnexpandedTypeOf _) -> again := true; expr
76-
| Error _ -> expr
76+
| Error e when Errors.is_unexpanded_module_type_of (e :> Errors.Tools_error.any) -> again := true; expr
77+
| Error _e ->
78+
expr
7779

7880
and functor_parameter env p =
7981
{ p with expr = module_type_expr env (p.id :> Id.Signature.t) p.expr}

0 commit comments

Comments
 (0)