Skip to content

Commit 09ea6b1

Browse files
authored
Fix uniqueness error of variables bound internal to a module (#3632)
* add test * fix * add comments
1 parent f027bd6 commit 09ea6b1

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

testsuite/tests/typing-unique/unique_mod_class.ml

+12
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,15 @@ let foo (local_ x : string ref) =
162162
[%%expect{|
163163
val foo : local_ string ref -> (unit -> < m : string >) = <fun>
164164
|}]
165+
166+
let () =
167+
let module M =
168+
struct
169+
let () =
170+
let x = "hello" in
171+
let _ = unique_id x in
172+
()
173+
end
174+
in ()
175+
[%%expect{|
176+
|}]

typing/uniqueness_analysis.ml

+22-5
Original file line numberDiff line numberDiff line change
@@ -2023,14 +2023,24 @@ let comp_pattern_match pat value =
20232023
| Some pat' -> pattern_match pat' value
20242024
| None -> Ienv.Extension.empty, UF.unused
20252025

2026-
let value_of_ident ienv unique_use occ path =
2026+
(** Given some [ienv], find the [Value.t] corresponding to an identifier.
2027+
2028+
There are two cases that it might be missing, both of which are related to
2029+
"module and class boundary" (see below):
2030+
- We are checking inside a module, and the identifier is refering to a value
2031+
defined outside of the module. In such case, we force this identifier to
2032+
[aliased].
2033+
- Another case is used by [open_variables]. See comments there.
2034+
*)
2035+
let value_of_ident ienv ?(force_missing = true) unique_use occ path =
20272036
match path with
20282037
| Path.Pident id -> (
20292038
match Ienv.find_opt id ienv with
20302039
(* TODO: for better error message, we should record in ienv why some
20312040
variables are not in it. *)
20322041
| None ->
2033-
force_aliased_boundary ~reason:Out_of_mod_class unique_use occ;
2042+
if force_missing
2043+
then force_aliased_boundary ~reason:Out_of_mod_class unique_use occ;
20342044
None
20352045
| Some paths ->
20362046
let value = Value.existing paths unique_use occ in
@@ -2042,8 +2052,8 @@ let value_of_ident ienv unique_use occ path =
20422052
None
20432053
| Path.Papply _ | Path.Pextra_ty _ -> assert false
20442054

2045-
(* TODO: replace the dirty hack.
2046-
The following functions are dirty hacks and used for modules and classes.
2055+
(* Module and class boundary
2056+
20472057
Currently we treat the boundary between modules/classes and their surrounding
20482058
environment coarsely. To be specific, all references in the modules/classes
20492059
pointing to the environment are treated as many and aliased. This translates
@@ -2061,8 +2071,15 @@ let open_variables ienv f =
20612071
(fun self e ->
20622072
(match e.exp_desc with
20632073
| Texp_ident (path, _, _, _, unique_use) -> (
2074+
(* We test if a variable is open by looking it up in the current
2075+
[ienv]: the [ienv] does not contain the internally-bound
2076+
variables in the module. In other words, open variables will be
2077+
found, and closed variables will be missing. For the latter, we
2078+
of course should not force them to [aliased]. *)
20642079
let occ = Occurrence.mk e.exp_loc in
2065-
match value_of_ident ienv unique_use occ path with
2080+
match
2081+
value_of_ident ienv ~force_missing:false unique_use occ path
2082+
with
20662083
| None -> ()
20672084
| Some value -> ll := value :: !ll)
20682085
| _ -> ());

0 commit comments

Comments
 (0)