@@ -398,38 +398,125 @@ let gen_rules ~sctx ~dir ~scope rest =
398398type instance =
399399 { new_name : Module_name .t
400400 ; lib_name : Module_name .t
401- ; args : (Module_name .t * Module_name .t ) list
401+ ; args : (Loc .t * Module_name .t * Module_name .t ) list
402+ ; loc : Loc .t
402403 }
403404
404405type instances =
405406 | Simple of instance
406- | Wrapped of Module_name .t * instance list
407+ | Wrapped of Loc .t * Module_name .t * instance list
408+
409+ module Errors = struct
410+ let make_resolve ?loc ?hints paragraphs =
411+ Resolve. fail
412+ (User_error. make
413+ ?loc
414+ ?hints
415+ paragraphs
416+ ~annots: (User_message.Annots. singleton User_message.Annots. needs_stack_trace () ))
417+ ;;
418+
419+ let make ?loc ?hints paragraphs = Memo. return @@ make_resolve ?loc ?hints paragraphs
420+
421+ let library_not_found ~loc name =
422+ make ~loc [ Pp. textf " Library parameter %S not found." (Lib_name. to_string name) ]
423+ ;;
424+
425+ let duplicate_parameters ~loc ~param arg arg' =
426+ make
427+ ~loc
428+ [ Pp. textf
429+ " Duplicate arguments %s and %s for parameter %s."
430+ (Lib_name. to_string (Lib. name arg))
431+ (Lib_name. to_string (Lib. name arg'))
432+ (Lib_name. to_string (Lib. name param))
433+ ]
434+ ;;
435+
436+ let missing_implements ~loc p =
437+ let name = Lib_name. to_string (Lib. name p) in
438+ make ~loc [ Pp. textf " Library %S does not implement a library parameter." name ]
439+ ;;
440+
441+ let unexpected_argument ?loc param arg =
442+ make
443+ ?loc
444+ [ Pp. textf
445+ " Argument %s implements unexpected parameter %s"
446+ (Lib_name. to_string (Lib. name arg))
447+ (Lib_name. to_string (Lib. name param))
448+ ]
449+ ~hints: [ Pp. text " Remove this argument" ]
450+ ;;
451+
452+ let new_name_already_used ?loc name =
453+ make
454+ ?loc
455+ [ Pp. textf " The instance name %s is already used." (Module_name. to_string name) ]
456+ ;;
457+
458+ let module_name_already_used ?loc name =
459+ make
460+ ?loc
461+ [ Pp. textf " Module name %s has already been used." (Module_name. to_string name) ]
462+ ;;
463+ end
407464
408465let instances ~sctx ~db (deps : Lib_dep.t list ) =
409466 let open Resolve.Memo.O in
410467 Resolve.Memo.List. concat_map deps ~f: (function
411468 | Lib_dep. Direct _ | Lib_dep. Re_export _ | Lib_dep. Select _ -> Resolve.Memo. return []
412- | Lib_dep. Instantiate { loc = _ ; lib; arguments; new_name } ->
413- let + entry_names =
414- let * lib = Resolve.Memo. lift_memo @@ Lib.DB. find db lib in
469+ | Lib_dep. Instantiate { loc; lib = lib_name ; arguments; new_name } ->
470+ let * lib = Resolve.Memo. lift_memo @@ Lib.DB. find db lib_name in
471+ let lib =
415472 match lib with
416- | None -> Resolve.Memo. return []
417- | Some lib -> Root_module. entry_module_names sctx lib
473+ | None -> Code_error. raise " lib not found" [ " lib" , Lib_name. to_dyn lib_name ]
474+ | Some lib -> lib
475+ in
476+ let * expected_params =
477+ let * parameters = Lib. parameters lib in
478+ let + module_names =
479+ Resolve.Memo.List. filter_map parameters ~f: Lib. main_module_name
480+ in
481+ Module_name.Map. of_list_map_exn module_names ~f: (fun m -> m, [] )
482+ in
483+ let + entry_names = Root_module. entry_module_names sctx lib
418484 and + args =
419- Resolve.Memo.List. filter_map arguments ~f: (fun (_loc , arg_name ) ->
420- let * arg = Resolve.Memo. lift_memo @@ Lib.DB. find db arg_name in
421- match arg with
422- | None -> Resolve.Memo. return None
423- | Some arg ->
424- (match Lib. implements arg with
425- | None -> Resolve.Memo. return None
426- | Some param ->
427- let * param = param in
428- let + param_name = Lib. main_module_name param
429- and + arg_name = Lib. main_module_name arg in
430- (match param_name, arg_name with
431- | Some param_name , Some arg_name -> Some (param_name, arg_name)
432- | _ -> None )))
485+ Resolve.Memo.List. fold_left
486+ arguments
487+ ~init: expected_params
488+ ~f: (fun args (loc , arg_name ) ->
489+ let * arg = Resolve.Memo. lift_memo @@ Lib.DB. find db arg_name in
490+ match arg with
491+ | None -> Errors. library_not_found ~loc arg_name
492+ | Some arg ->
493+ (match Lib. implements arg with
494+ | None -> Errors. missing_implements ~loc arg
495+ | Some param ->
496+ let * param = param in
497+ let * param_name = Lib. main_module_name param
498+ and * arg_name = Lib. main_module_name arg in
499+ (match param_name, arg_name with
500+ | Some param_name , Some arg_name ->
501+ (match Module_name.Map. find args param_name with
502+ | Some [] ->
503+ Resolve.Memo. return
504+ @@ Module_name.Map. add_multi args param_name (loc, arg, arg_name)
505+ | None -> Errors. unexpected_argument ~loc arg param
506+ | Some ((_ , existing , _ ) :: _ ) ->
507+ Errors. duplicate_parameters ~loc ~param existing arg)
508+ | None , None | Some _ , None | None , Some _ ->
509+ Errors. missing_implements ~loc arg)))
510+ in
511+ let args =
512+ Module_name.Map. foldi args ~init: [] ~f: (fun param arg_opt acc ->
513+ match arg_opt with
514+ | [] -> acc
515+ | [ (loc, _lib, arg) ] -> (loc, param, arg) :: acc
516+ | (_ , arg , _ ) :: (_ , arg' , _ ) :: _ ->
517+ Code_error. raise
518+ " duplicate arguments were already reported"
519+ [ " arg" , Lib. to_dyn arg; " arg'" , Lib. to_dyn arg' ])
433520 in
434521 (match entry_names with
435522 | [] -> []
@@ -439,15 +526,55 @@ let instances ~sctx ~db (deps : Lib_dep.t list) =
439526 | None -> entry_name
440527 | Some new_name -> new_name
441528 in
442- [ Simple { new_name; lib_name = entry_name; args } ]
529+ [ Simple { new_name; lib_name = entry_name; args; loc } ]
443530 | _ :: _ :: _ ->
444531 let instances =
445532 List. map entry_names ~f: (fun name ->
446- { new_name = name; lib_name = name; args })
533+ { new_name = name; lib_name = name; args; loc })
447534 in
448535 (match new_name with
449536 | None -> List. map ~f: (fun i -> Simple i) instances
450- | Some new_name -> [ Wrapped (new_name, instances) ])))
537+ | Some new_name -> [ Wrapped (loc, new_name, instances) ])))
538+ ;;
539+
540+ let check_instance known_names instance =
541+ if Module_name.Set. mem known_names instance.new_name
542+ then Errors. new_name_already_used ~loc: instance.loc instance.new_name
543+ else if Module_name.Set. mem known_names instance.lib_name
544+ then Errors. module_name_already_used ~loc: instance.loc instance.new_name
545+ else
546+ let open Resolve.Memo.O in
547+ let + () =
548+ Resolve.Memo.List. iter instance.args ~f: (fun (loc , _param_name , arg_name ) ->
549+ if Module_name.Set. mem known_names arg_name
550+ then Errors. module_name_already_used ~loc instance.new_name
551+ else Resolve.Memo. return () )
552+ in
553+ Module_name.Set. add known_names instance.new_name
554+ ;;
555+
556+ let check_instances instances =
557+ let open Resolve.Memo.O in
558+ Resolve.Memo.List. fold_left
559+ instances
560+ ~init: Module_name.Set. empty
561+ ~f: (fun acc -> function
562+ | Simple instance -> check_instance acc instance
563+ | Wrapped (loc , wrapped_name , instances ) ->
564+ if Module_name.Set. mem acc wrapped_name
565+ then Errors. new_name_already_used ~loc wrapped_name
566+ else
567+ let + _sub_definitions : Module_name.Set. t =
568+ Resolve.Memo.List. fold_left instances ~init: acc ~f: check_instance
569+ in
570+ Module_name.Set. add acc wrapped_name)
571+ ;;
572+
573+ let instances ~sctx ~db deps =
574+ let open Resolve.Memo.O in
575+ let * instances = instances ~sctx ~db deps in
576+ let + _ = check_instances instances in
577+ instances
451578;;
452579
453580let print_instance b indent instance =
@@ -458,7 +585,7 @@ let print_instance b indent instance =
458585 (Module_name. to_string instance.new_name)
459586 (Module_name. to_string instance.lib_name)
460587 (String. concat ~sep: " "
461- @@ List. map instance.args ~f: (fun (param_name , arg_name ) ->
588+ @@ List. map instance.args ~f: (fun (_loc , param_name , arg_name ) ->
462589 Printf. sprintf
463590 " (%s)(%s)"
464591 (Module_name. to_string param_name)
@@ -469,7 +596,7 @@ let print_instances b instances =
469596 List. iter instances ~f: (fun instances ->
470597 match instances with
471598 | Simple instance -> print_instance b " " instance
472- | Wrapped (new_name , instances ) ->
599+ | Wrapped (_loc , new_name , instances ) ->
473600 Printf. bprintf b " \n module %s = struct" (Module_name. to_string new_name);
474601 List. iter instances ~f: (print_instance b " " );
475602 Printf. bprintf b " \n end\n " )
0 commit comments