Skip to content

Commit a97f813

Browse files
committed
fix: Properly type samplers
1 parent 787840b commit a97f813

File tree

1 file changed

+68
-40
lines changed

1 file changed

+68
-40
lines changed

src/grader/introspection.ml

Lines changed: 68 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -206,52 +206,80 @@ let print_value ppf v ty =
206206
Format.fprintf ppf "@]"
207207
end
208208

209+
210+
(* for a type [('a, 'b) foo] => [register_sampler "foo" f] where [f] must have
211+
type ['a sampler -> 'b sampler -> ('a, 'b) foo sampler].
212+
- find the sampler's type from its name and the cmi
213+
- lookup type [foo]
214+
- build the expected sampler type from the type params of [foo]
215+
- match with the sampler type
216+
*)
209217
let register_sampler name f =
210-
let sampler_name = "sample_" ^ name in
211-
(* FIXME TODO: type-check the specified samplers ! *)
212-
(* let sampled_ty_path, sampled_ty_decl =
213-
* Env.find_type_by_name (Longident.Lident name) !Toploop.toplevel_env
214-
* in
215-
* let sampled_ty =
216-
* match sampled_ty_decl.Types.type_manifest with
217-
* | Some ty -> ty
218-
* | None -> failwith "Type is not public for sampling"
219-
* in
220-
* let sampler_ty_computed =
221-
* (\* The given sampler must be a function with one argument for every type param *\)
222-
* let sampler ty = (\* ['a sampler] == [unit -> 'a] *\)
223-
* Types.Tarrow (Asttypes.Nolabel, Predef.type_unit, ty, Types.Cok)
224-
* in
225-
* List.fold_right (fun typaram ty ->
226-
* Types.Tarrow (Asttypes.Nolabel, Btype.newgenty (sampler typaram), Btype.newgenty ty, Types.Cok))
227-
* sampled_ty_decl.Types.type_params
228-
* (sampler sampled_ty)
229-
* in *)
230-
let sampler_ty(* _found *) =
231-
Env.find_value
232-
(Path.Pdot (Path.Pident (Ident.create_persistent "Test"), sampler_name))
233-
!Toploop.toplevel_env
234-
(* Requires [test.cmi] to be pre-loaded *)
235-
(* FIXME: maybe don't require the cmi and skip this check when on the
236-
browser.
237-
... unless the type of the sampler might somehow depend on the types
238-
inferred from [Code], but that should definitely be forbidden! *)
218+
let open Types in
219+
let gen_sampler_type =
220+
Path.Pdot
221+
(Path.Pident (Ident.create_persistent "Test_lib"),
222+
"sampler")
239223
in
240-
if true (* Ctype.moregeneral !Toploop.toplevel_env true
241-
* (Btype.newgenty sampler_ty_found) sampler_ty_computed *)
242-
then
243-
(Toploop.toplevel_env :=
244-
Env.add_value (Ident.create_local sampler_name) sampler_ty
245-
!Toploop.toplevel_env;
246-
Toploop.setvalue sampler_name (Obj.repr f))
247-
else
248-
failwith "sampler has the wrong type !"
249-
224+
let lookup_env = !Toploop.toplevel_env in
225+
let sampler_name = "sample_" ^ name in
226+
match
227+
let sampler_path =
228+
Path.Pdot (Path.Pident (Ident.create_persistent "Test"),
229+
sampler_name)
230+
in
231+
try sampler_path, Env.find_value sampler_path lookup_env
232+
with Not_found ->
233+
Env.find_value_by_name (Longident.Lident sampler_name)
234+
lookup_env
235+
with
236+
| exception Not_found ->
237+
Format.ksprintf failwith "Bad sampler registration (function %s not found).@."
238+
sampler_name
239+
| _sampler_path, sampler_desc ->
240+
match
241+
Env.find_type_by_name (Longident.Lident name) lookup_env
242+
with
243+
| exception Not_found ->
244+
Format.eprintf "Warning: unrecognised sampler definition (type %s not found).@."
245+
name
246+
| sampled_ty_path, sampled_ty_decl ->
247+
let sampler_ty_expected =
248+
Ctype.begin_def();
249+
let ty_args =
250+
List.map (fun _ -> Ctype.newvar ()) sampled_ty_decl.type_params
251+
in
252+
let ty_target =
253+
Ctype.newty (Tconstr (sampled_ty_path, ty_args, ref Mnil))
254+
in
255+
let fn_args =
256+
List.map (fun ty -> Ctype.newconstr gen_sampler_type [ty]) ty_args
257+
in
258+
let sampler_ty =
259+
List.fold_right (fun fn_arg ty ->
260+
Ctype.newty (Tarrow (Asttypes.Nolabel, fn_arg, ty, Cunknown)))
261+
fn_args (Ctype.newconstr gen_sampler_type [ty_target])
262+
in
263+
Ctype.end_def ();
264+
Ctype.generalize sampler_ty;
265+
sampler_ty
266+
in
267+
(try
268+
Ctype.unify lookup_env
269+
sampler_ty_expected
270+
(Ctype.instance sampler_desc.val_type)
271+
with Ctype.Unify _ ->
272+
Format.ksprintf failwith "%s has a wrong type for a sampling function.@."
273+
sampler_name);
274+
Toploop.toplevel_env :=
275+
Env.add_value (Ident.create_local sampler_name) sampler_desc
276+
!Toploop.toplevel_env;
277+
Toploop.setvalue sampler_name (Obj.repr f)
250278

251279
let sample_value ty =
252280
let { Typedtree.ctyp_type = ty; _ } =
253281
Typetexp.transl_type_scheme !Toploop.toplevel_env (Ty.obj ty) in
254-
let lid = Format.asprintf "sample_%04X" (Random.int 0xFFFF) in
282+
let lid = Format.asprintf "sample_%06X" (Random.int 0xFFFFFF) in
255283
let phrase =
256284
let open Asttypes in
257285
let open Types in

0 commit comments

Comments
 (0)