From e11fae9753cd12af7d2ee3cb2784a29c529af5b9 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 8 Oct 2024 14:43:19 +0100 Subject: [PATCH 01/23] basic conversion suggestion --- src/mo_frontend/typing.ml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index f3aedaa4943..6ecfd67f24d 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -1992,12 +1992,36 @@ and check_exp' env0 t exp : T.typ = | _ -> let t' = infer_exp env0 exp in if not (T.sub t' t) then + begin local_error env0 exp.at "M0096" "expression of type%a\ncannot produce expected type%a" display_typ_expand t' display_typ_expand t; + suggest_conversion env0 exp.at t' t + end; t' +and suggest_conversion env at ty1 ty2 = + T.(match promote ty1, promote ty2 with + | Prim p1, Prim p2 -> + let id1 = String.trim(string_of_prim p1) in + let id2 = String.trim(string_of_prim p2) in + let find pre id1 id2 = + match T.Env.find_opt id1 env.vals with + | Some (ty1, _, _, _) -> + (match T.promote ty1 with + | T.Obj(_, tfs) -> + (match T.lookup_val_field_opt (pre^id2) tfs with + | Some ty -> + info env at "Maybe try conversion %s.%s%s" id1 pre id2 + | None -> ()) + | _ -> ()) + | None -> () + in + find "to" id1 id2; + find "from" id2 id1 + | _ -> ()) + and check_exp_field env (ef : exp_field) fts = let { mut; id; exp } = ef.it in let ft_opt = List.find_opt (fun ft -> ft.T.lab = id.it) fts in From b72505dff53928c7b4b97aa03841b39660595adf Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Mon, 28 Oct 2024 17:12:16 +0000 Subject: [PATCH 02/23] add all imports --- src/pipeline/resolve_import.ml | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/pipeline/resolve_import.ml b/src/pipeline/resolve_import.ml index 7a6290d69ce..70f685fad1b 100644 --- a/src/pipeline/resolve_import.ml +++ b/src/pipeline/resolve_import.ml @@ -249,6 +249,49 @@ type resolved_flags = { actor_idl_path : actor_idl_path; } + +let list_files_recursively : string -> string list = + fun dir -> + let rec loop result = function + | f :: fs when Sys.is_directory f -> + Sys.readdir f + |> Array.to_list + |> List.map (Filename.concat f) + |> List.append fs + |> loop result + | f :: fs -> loop (f :: result) fs + | [] -> result + in + loop [] [ dir ] + +let list_files : string -> (string * string) list = + fun source -> + (* Printf.printf "%s -> %s\n" source output; *) + let all_files = list_files_recursively source in + let all_files = + List.filter (fun f -> Filename.extension f = ".mo") all_files + in + List.map + (fun file -> + file + (* |> Lib.FilePath.relative_to source + |> Option.get *) + |> fun f -> (file, f)) + all_files + +let package_imports base packages = + let imports = M.fold (fun pname url acc -> + if base = url then acc else + let files = list_files url in + (files |> List.map (fun (file, path) -> + LibPath {package = Some pname; + path = path} + (* @@ no_region *)) ) :: + acc) packages [] + in + List.concat imports + + let resolve_flags : flags -> resolved_flags Diag.result = fun { actor_idl_path; package_urls; actor_aliases } -> let open Diag.Syntax in @@ -263,8 +306,12 @@ let resolve let* { packages; aliases; actor_idl_path } = resolve_flags flags in Diag.with_message_store (fun msgs -> let base = if Sys.is_directory base then base else Filename.dirname base in - let imported = ref RIM.empty in - List.iter (resolve_import_string msgs base actor_idl_path aliases packages imported) (prog_imports p); + (* let imported = ref RIM.empty in *) + let imported = + ref (List.fold_right (fun ri rim -> RIM.add ri Source.no_region rim) + (package_imports base packages) RIM.empty) + in + List.iter (resolve_import_string msgs base actor_idl_path aliases packages imported)(prog_imports p); Some (List.map (fun (rim,at) -> rim @@ at) (RIM.bindings !imported)) ) From 7f4a76f15b7b56df99843418c57fb4415e0466b3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Tue, 29 Oct 2024 21:17:34 +0000 Subject: [PATCH 03/23] search imported and non-imported libs for direct conversions (need to fix literal patterns) --- src/mo_frontend/typing.ml | 129 +++++++++++++++++++++++--------------- 1 file changed, 79 insertions(+), 50 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 0f5f03dcf57..da5b2be5843 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -114,32 +114,6 @@ let kind_of_field_pattern pf = match pf.it with | { id; pat = { it = VarP pat_id; _ } } when id = pat_id -> Scope.FieldReference | _ -> Scope.Declaration -(* Suggestions *) - -let suggest desc id ids = - if !Flags.ai_errors then - Printf.sprintf - "\nThe %s %s is not available. Try something else?" - desc - id - else - let suggestions = - let limit = Lib.Int.log2 (String.length id) in - let distance = Lib.String.levenshtein_distance id in - let weighted_ids = List.filter_map (fun id0 -> - let d = distance id0 in - if Lib.String.starts_with id id0 || d <= limit then - Some (d, id0) - else None) ids in - List.sort compare weighted_ids |> List.map snd - in - if suggestions = [] then "" - else - let rest, last = Lib.List.split_last suggestions in - Printf.sprintf "\nDid you mean %s %s?" - desc - ((if rest <> [] then (String.concat ", " rest) ^ " or " else "") ^ last) - (* Error bookkeeping *) exception Recover @@ -316,6 +290,80 @@ let leave_scope env inner_identifiers initial_usage = let final_usage = S.union initial_usage unshadowed_usage in env.used_identifiers := final_usage +(* Suggestions *) + +let suggest desc id ids = + if !Flags.ai_errors then + Printf.sprintf + "\nThe %s %s is not available. Try something else?" + desc + id + else + let suggestions = + let limit = Lib.Int.log2 (String.length id) in + let distance = Lib.String.levenshtein_distance id in + let weighted_ids = List.filter_map (fun id0 -> + let d = distance id0 in + if Lib.String.starts_with id id0 || d <= limit then + Some (d, id0) + else None) ids in + List.sort compare weighted_ids |> List.map snd + in + if suggestions = [] then "" + else + let rest, last = Lib.List.split_last suggestions in + Printf.sprintf "\nDid you mean %s %s?" + desc + ((if rest <> [] then (String.concat ", " rest) ^ " or " else "") ^ last) + +let suggest_conversion env at ty1 ty2 = + T.(match promote ty1, promote ty2 with + | Prim p1, Prim p2 -> + let rec search_obj lib import path ty = + match T.promote ty with + | T.Obj(_, tfs) -> + tfs |> + List.iter (fun {lab;typ;_} -> + match T.normalize typ with + | T.Func _ when + (Lib.String.starts_with "to" lab || + Lib.String.starts_with "from" lab) && + T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> + (match lib, import with + | Some id, _ -> + info env at "maybe try conversion `%s.%s%s(_)`" id path lab + | None, Some (id, package, rel_name) -> + info env at + "maybe try conversion `%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" + id path lab id package rel_name + | _ -> ()) + | T.Obj(_, tfs) as ty1 -> + search_obj lib import (path^lab^".") ty1 + | _ -> ()) + | _ -> () + in + T.Env.iter (fun filename ty -> + if Lib.String.starts_with "@" filename then () else + let imported_name = T.Env.fold (fun id (ty1, _, _, _) acc -> + if ty == ty1 then Some id else acc) env.vals None + in + let import = + if imported_name <> None then None else + Flags.M.fold (fun package path acc -> + let base = Lib.FilePath.normalise path in + (* Printf.printf "base %s filename %s" base filename; *) + if Lib.FilePath.is_subpath base filename then + let Some rel_path = Lib.FilePath.relative_to base filename in + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in + Some (id, package, rel_name) + else acc) + (!Flags.package_urls) None + in + search_obj imported_name import "" ty) env.libs + | _ -> ()) + + (* Value environments *) let singleton id t = T.Env.singleton id.it (t, id.at, Scope.Declaration) @@ -1155,11 +1203,13 @@ let check_lit env t lit at = | t, _ -> let t' = T.Prim (infer_lit env lit at) in if not (T.sub t' t) then - error env at "M0050" + begin + local_error env at "M0050" "literal of type%a\ndoes not have expected type%a" display_typ t' - display_typ_expand t - + display_typ_expand t; + suggest_conversion env at t' t + end (* Coercions *) @@ -2001,27 +2051,6 @@ and check_exp' env0 t exp : T.typ = end; t' -and suggest_conversion env at ty1 ty2 = - T.(match promote ty1, promote ty2 with - | Prim p1, Prim p2 -> - let id1 = String.trim(string_of_prim p1) in - let id2 = String.trim(string_of_prim p2) in - let find pre id1 id2 = - match T.Env.find_opt id1 env.vals with - | Some (ty1, _, _, _) -> - (match T.promote ty1 with - | T.Obj(_, tfs) -> - (match T.lookup_val_field_opt (pre^id2) tfs with - | Some ty -> - info env at "Maybe try conversion %s.%s%s" id1 pre id2 - | None -> ()) - | _ -> ()) - | None -> () - in - find "to" id1 id2; - find "from" id2 id1 - | _ -> ()) - and check_exp_field env (ef : exp_field) fts = let { mut; id; exp } = ef.it in let ft_opt = List.find_opt (fun ft -> ft.T.lab = id.it) fts in From daea242db32c8aca170f2bb9a825361f71252cee Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 12:08:27 +0000 Subject: [PATCH 04/23] refactor; suppress hints on literal patterns --- src/mo_frontend/typing.ml | 61 ++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index da5b2be5843..17c035d9c6f 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -316,10 +316,12 @@ let suggest desc id ids = desc ((if rest <> [] then (String.concat ", " rest) ^ " or " else "") ^ last) + +type lib_sort = Imported of string | NonImported of {id : string; package : string; rel_name : string } let suggest_conversion env at ty1 ty2 = T.(match promote ty1, promote ty2 with | Prim p1, Prim p2 -> - let rec search_obj lib import path ty = + let rec search_obj lib_sort path ty = match T.promote ty with | T.Obj(_, tfs) -> tfs |> @@ -329,41 +331,46 @@ let suggest_conversion env at ty1 ty2 = (Lib.String.starts_with "to" lab || Lib.String.starts_with "from" lab) && T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> - (match lib, import with - | Some id, _ -> + (match lib_sort with + | Imported id -> info env at "maybe try conversion `%s.%s%s(_)`" id path lab - | None, Some (id, package, rel_name) -> + | NonImported {id; package; rel_name} -> info env at "maybe try conversion `%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" - id path lab id package rel_name - | _ -> ()) + id path lab id package rel_name) | T.Obj(_, tfs) as ty1 -> - search_obj lib import (path^lab^".") ty1 + search_obj lib_sort (path^lab^".") ty1 | _ -> ()) | _ -> () in T.Env.iter (fun filename ty -> - if Lib.String.starts_with "@" filename then () else + if Lib.String.starts_with "@" filename + then () (* skip prim etc *) + else let imported_name = T.Env.fold (fun id (ty1, _, _, _) acc -> - if ty == ty1 then Some id else acc) env.vals None + if ty == ty1 then Some id else acc) env.vals None in - let import = - if imported_name <> None then None else + let lib_sort_opt = match imported_name with + | Some id -> Some (Imported id) + | None -> Flags.M.fold (fun package path acc -> - let base = Lib.FilePath.normalise path in - (* Printf.printf "base %s filename %s" base filename; *) - if Lib.FilePath.is_subpath base filename then - let Some rel_path = Lib.FilePath.relative_to base filename in - let rel_name = Filename.chop_extension rel_path in - let id = Filename.basename rel_name in - Some (id, package, rel_name) - else acc) - (!Flags.package_urls) None + let base = Lib.FilePath.normalise path in + if Lib.FilePath.is_subpath base filename then + match Lib.FilePath.relative_to base filename with + | None -> None + | Some rel_path -> + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in + Some (NonImported {id; package; rel_name}) + else acc) + (!Flags.package_urls) None in - search_obj imported_name import "" ty) env.libs + match lib_sort_opt with + | None -> () + | Some lib_sort -> search_obj lib_sort "" ty) + env.libs | _ -> ()) - (* Value environments *) let singleton id t = T.Env.singleton id.it (t, id.at, Scope.Declaration) @@ -1174,7 +1181,7 @@ let infer_lit env lit at : T.prim = | PreLit _ -> assert false -let check_lit env t lit at = +let check_lit env t lit at suggest = match t, !lit with | T.Prim T.Nat, PreLit (s, T.Nat) -> lit := NatLit (check_nat env at s) @@ -1208,7 +1215,7 @@ let check_lit env t lit at = "literal of type%a\ndoes not have expected type%a" display_typ t' display_typ_expand t; - suggest_conversion env at t' t + if suggest then suggest_conversion env at t' t end (* Coercions *) @@ -1868,7 +1875,7 @@ and check_exp' env0 t exp : T.typ = | PrimE s, T.Func _ -> t | LitE lit, _ -> - check_lit env t lit exp.at; + check_lit env t lit exp.at true; t | ActorUrlE exp', t' -> check_exp_strong env T.text exp'; @@ -2321,7 +2328,7 @@ and check_pat_aux' env t pat val_kind : Scope.val_env = display_typ_expand t; if T.sub t' T.Non then ignore (infer_lit env lit pat.at) - else check_lit env t' lit pat.at + else check_lit env t' lit pat.at false end; T.Env.empty | SignP (op, lit) -> @@ -2332,7 +2339,7 @@ and check_pat_aux' env t pat val_kind : Scope.val_env = display_typ_expand t; if T.sub t' T.Non then ignore (infer_lit env lit pat.at) - else check_lit env t' lit pat.at + else check_lit env t' lit pat.at false end; T.Env.empty | TupP pats -> From 239493d7afe0e7a6e7b3be9630b1f002b696066e Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 15:19:06 +0000 Subject: [PATCH 05/23] suppress errors in package libs --- src/mo_frontend/typing.ml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 17c035d9c6f..086d8e60e1c 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -57,6 +57,7 @@ type env = unused_warnings : unused_warnings ref; reported_stable_memory : bool ref; viper_mode : bool; + errors_only : bool; } let env_of_scope ?(viper_mode=false) msgs scope = @@ -79,6 +80,7 @@ let env_of_scope ?(viper_mode=false) msgs scope = used_identifiers = ref S.empty; unused_warnings = ref []; reported_stable_memory = ref false; + errors_only = false; viper_mode; } @@ -193,10 +195,12 @@ let local_error env at code fmt = Format.kasprintf (fun s -> Diag.add_msg env.msgs (type_error at code s)) fmt let warn env at code fmt = - Format.kasprintf (fun s -> Diag.add_msg env.msgs (type_warning at code s)) fmt + Format.kasprintf (fun s -> + if not env.errors_only then Diag.add_msg env.msgs (type_warning at code s)) fmt let info env at fmt = - Format.kasprintf (fun s -> Diag.add_msg env.msgs (type_info at s)) fmt + Format.kasprintf (fun s -> + if not env.errors_only then Diag.add_msg env.msgs (type_info at s)) fmt let check_deprecation env at desc id depr = match depr with @@ -3167,7 +3171,7 @@ let check_lib scope pkg_opt lib : Scope.t Diag.result = (fun msgs -> recover_opt (fun lib -> - let env = env_of_scope msgs scope in + let env = { (env_of_scope msgs scope) with errors_only = (pkg_opt <> None) } in let { imports; body = cub; _ } = lib.it in let (imp_ds, ds) = CompUnit.decs_of_lib lib in let typ, _ = infer_block env (imp_ds @ ds) lib.at false in From b60c1d0ec0aab7d47486cebea2f7cfc1b61b1725 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 16:02:11 +0000 Subject: [PATCH 06/23] adjust tests; introduce separate pkg dir so all files under pkg are error free --- src/mo_frontend/typing.ml | 3 ++- test/fail/ok/one-tuple-ambiguity.tc.ok | 3 +++ test/fail/ok/unused.tc.ok | 4 ++-- test/fail/{lib => pkg}/unused1.mo | 0 test/fail/{lib => pkg}/unused2.mo | 2 +- test/fail/{lib => pkg}/unused3.mo | 0 test/fail/{lib => pkg}/unused4.mo | 0 test/fail/unused.mo | 6 +++--- 8 files changed, 11 insertions(+), 7 deletions(-) rename test/fail/{lib => pkg}/unused1.mo (100%) rename test/fail/{lib => pkg}/unused2.mo (70%) rename test/fail/{lib => pkg}/unused3.mo (100%) rename test/fail/{lib => pkg}/unused4.mo (100%) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 086d8e60e1c..632208285e5 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -1215,7 +1215,8 @@ let check_lit env t lit at suggest = let t' = T.Prim (infer_lit env lit at) in if not (T.sub t' t) then begin - local_error env at "M0050" + (if suggest then local_error else error) + env at "M0050" "literal of type%a\ndoes not have expected type%a" display_typ t' display_typ_expand t; diff --git a/test/fail/ok/one-tuple-ambiguity.tc.ok b/test/fail/ok/one-tuple-ambiguity.tc.ok index f0810e0998e..238650a2ca4 100644 --- a/test/fail/ok/one-tuple-ambiguity.tc.ok +++ b/test/fail/ok/one-tuple-ambiguity.tc.ok @@ -2,3 +2,6 @@ one-tuple-ambiguity.mo:16.3-16.5: type error [M0050], literal of type Nat does not have expected type (Nat, Bool) +one-tuple-ambiguity.mo:16.1-16.5: type error [M0097], expected function type, but expression produces type + () +one-tuple-ambiguity.mo:16.5-16.6: info, this looks like an unintended function call, perhaps a missing ';'? diff --git a/test/fail/ok/unused.tc.ok b/test/fail/ok/unused.tc.ok index 80df6352cc8..891ab0fff39 100644 --- a/test/fail/ok/unused.tc.ok +++ b/test/fail/ok/unused.tc.ok @@ -1,5 +1,5 @@ -lib/unused4.mo:4.7-4.14: warning [M0194], unused identifier unused4 (delete or rename to wildcard `_` or `_unused4`) -lib/unused2.mo:7.7-7.14: warning [M0194], unused identifier unused2 (delete or rename to wildcard `_` or `_unused2`) +pkg/unused4.mo:4.7-4.14: warning [M0194], unused identifier unused4 (delete or rename to wildcard `_` or `_unused4`) +pkg/unused2.mo:7.7-7.14: warning [M0194], unused identifier unused2 (delete or rename to wildcard `_` or `_unused2`) unused.mo:7.6-7.9: warning [M0194], unused identifier rec (delete or rename to wildcard `_` or `_rec`) unused.mo:9.9-9.15: warning [M0194], unused identifier unused (delete or rename to wildcard `_` or `_unused`) unused.mo:11.6-11.7: warning [M0194], unused identifier g (delete or rename to wildcard `_` or `_g`) diff --git a/test/fail/lib/unused1.mo b/test/fail/pkg/unused1.mo similarity index 100% rename from test/fail/lib/unused1.mo rename to test/fail/pkg/unused1.mo diff --git a/test/fail/lib/unused2.mo b/test/fail/pkg/unused2.mo similarity index 70% rename from test/fail/lib/unused2.mo rename to test/fail/pkg/unused2.mo index 76b55a11c14..26dd9544c55 100644 --- a/test/fail/lib/unused2.mo +++ b/test/fail/pkg/unused2.mo @@ -1,4 +1,4 @@ -import _Unused1 "mo:lib/unused3"; // don't report package imports usage warning +import _Unused1 "mo:pkg/unused3"; // don't report package imports usage warning import _Unused2 "unused4"; // do report relative imports usage warning module { diff --git a/test/fail/lib/unused3.mo b/test/fail/pkg/unused3.mo similarity index 100% rename from test/fail/lib/unused3.mo rename to test/fail/pkg/unused3.mo diff --git a/test/fail/lib/unused4.mo b/test/fail/pkg/unused4.mo similarity index 100% rename from test/fail/lib/unused4.mo rename to test/fail/pkg/unused4.mo diff --git a/test/fail/unused.mo b/test/fail/unused.mo index fe9b34d4c0a..4a7c8d00581 100644 --- a/test/fail/unused.mo +++ b/test/fail/unused.mo @@ -1,6 +1,6 @@ -//MOC-FLAG --package lib lib -import _Unused1 "mo:lib/unused1"; // don't report package imports usage warning -import _Unused2 "./lib/unused2"; // do report relative imports usage warning +//MOC-FLAG --package pkg pkg +import _Unused1 "mo:pkg/unused1"; // don't report package imports usage warning +import _Unused2 "./pkg/unused2"; // do report relative imports usage warning func rec1() { rec1() }; // accepted, but reject as unused? From 6ac43ae1d8f9e95a7adfb6269fec11477afa6bc7 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 16:48:53 +0000 Subject: [PATCH 07/23] only include all libs with --ai-errors --- src/languageServer/declaration_index.ml | 1 + src/pipeline/pipeline.ml | 3 +- src/pipeline/resolve_import.ml | 46 +++++++++++-------------- src/pipeline/resolve_import.mli | 2 ++ 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/languageServer/declaration_index.ml b/src/languageServer/declaration_index.ml index 105d4fd8408..ea54c609524 100644 --- a/src/languageServer/declaration_index.ml +++ b/src/languageServer/declaration_index.ml @@ -188,6 +188,7 @@ let empty : string -> t = package_urls = !Flags.package_urls; actor_aliases = !Flags.actor_aliases; actor_idl_path = !Flags.actor_idl_path; + include_all_libs = false (* TBR *) }) in { diff --git a/src/pipeline/pipeline.ml b/src/pipeline/pipeline.ml index 630abc386f8..02c4ad7815c 100644 --- a/src/pipeline/pipeline.ml +++ b/src/pipeline/pipeline.ml @@ -142,7 +142,8 @@ let resolve_flags () = ResolveImport.{ package_urls = !Flags.package_urls; actor_aliases = !Flags.actor_aliases; - actor_idl_path = !Flags.actor_idl_path + actor_idl_path = !Flags.actor_idl_path; + include_all_libs = !Flags.ai_errors; } let resolve_prog (prog, base) : resolve_result = diff --git a/src/pipeline/resolve_import.ml b/src/pipeline/resolve_import.ml index 70f685fad1b..5e768f3f8f8 100644 --- a/src/pipeline/resolve_import.ml +++ b/src/pipeline/resolve_import.ml @@ -241,6 +241,7 @@ type flags = { package_urls : package_urls; actor_aliases : actor_aliases; actor_idl_path : actor_idl_path; + include_all_libs : bool; } type resolved_flags = { @@ -264,36 +265,25 @@ let list_files_recursively : string -> string list = in loop [] [ dir ] -let list_files : string -> (string * string) list = - fun source -> - (* Printf.printf "%s -> %s\n" source output; *) - let all_files = list_files_recursively source in - let all_files = +let list_files : string -> string list = + fun source -> + let all_files = list_files_recursively source in List.filter (fun f -> Filename.extension f = ".mo") all_files - in - List.map - (fun file -> - file - (* |> Lib.FilePath.relative_to source - |> Option.get *) - |> fun f -> (file, f)) - all_files let package_imports base packages = let imports = M.fold (fun pname url acc -> - if base = url then acc else + if base = url then + acc + else let files = list_files url in - (files |> List.map (fun (file, path) -> - LibPath {package = Some pname; - path = path} - (* @@ no_region *)) ) :: - acc) packages [] - in - List.concat imports + List.map (fun path -> LibPath {package = Some pname; path = path}) files::acc) + packages [] + in + List.concat imports let resolve_flags : flags -> resolved_flags Diag.result - = fun { actor_idl_path; package_urls; actor_aliases } -> + = fun { actor_idl_path; package_urls; actor_aliases; _ } -> let open Diag.Syntax in let* packages = resolve_packages package_urls in let* aliases = resolve_aliases actor_aliases in @@ -306,11 +296,15 @@ let resolve let* { packages; aliases; actor_idl_path } = resolve_flags flags in Diag.with_message_store (fun msgs -> let base = if Sys.is_directory base then base else Filename.dirname base in - (* let imported = ref RIM.empty in *) let imported = - ref (List.fold_right (fun ri rim -> RIM.add ri Source.no_region rim) - (package_imports base packages) RIM.empty) - in + ref (if flags.include_all_libs + then (* add all available package libraries *) + (List.fold_right (fun ri rim -> RIM.add ri Source.no_region rim) + (package_imports base packages) RIM.empty) + else + (* consder only the explicitly imported package libraries *) + RIM.empty) + in List.iter (resolve_import_string msgs base actor_idl_path aliases packages imported)(prog_imports p); Some (List.map (fun (rim,at) -> rim @@ at) (RIM.bindings !imported)) ) diff --git a/src/pipeline/resolve_import.mli b/src/pipeline/resolve_import.mli index 171001c7331..5efd7eb338a 100644 --- a/src/pipeline/resolve_import.mli +++ b/src/pipeline/resolve_import.mli @@ -18,6 +18,7 @@ type flags = { package_urls : package_urls; actor_aliases : actor_aliases; actor_idl_path : actor_idl_path; + include_all_libs : bool; } type package_map = filepath Flags.M.t @@ -28,6 +29,7 @@ type resolved_flags = { aliases : aliases; actor_idl_path : actor_idl_path; } + val resolve_flags : flags -> resolved_flags Diag.result val resolve : flags -> Syntax.prog -> filepath -> resolved_imports Diag.result From 75372a2270ea21c1942f0abd1fba5256b520a30a Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 20:38:37 +0000 Subject: [PATCH 08/23] fix bug with packages specified with relative paths --- src/mo_frontend/typing.ml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 632208285e5..a6e2189a56f 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -337,11 +337,13 @@ let suggest_conversion env at ty1 ty2 = T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> (match lib_sort with | Imported id -> - info env at "maybe try conversion `%s.%s%s(_)`" id path lab + info env at + "maybe try conversion `%s.%s%s(_)`" + id path lab | NonImported {id; package; rel_name} -> - info env at - "maybe try conversion `%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" - id path lab id package rel_name) + info env at + "maybe try conversion `%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" + id path lab id package rel_name) | T.Obj(_, tfs) as ty1 -> search_obj lib_sort (path^lab^".") ty1 | _ -> ()) @@ -359,14 +361,12 @@ let suggest_conversion env at ty1 ty2 = | None -> Flags.M.fold (fun package path acc -> let base = Lib.FilePath.normalise path in - if Lib.FilePath.is_subpath base filename then - match Lib.FilePath.relative_to base filename with - | None -> None - | Some rel_path -> - let rel_name = Filename.chop_extension rel_path in - let id = Filename.basename rel_name in - Some (NonImported {id; package; rel_name}) - else acc) + match Lib.FilePath.relative_to base filename with + | None -> acc + | Some rel_path -> + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in + Some (NonImported {id; package; rel_name})) (!Flags.package_urls) None in match lib_sort_opt with From ff645c58dbcfa3c85dc01b65f4f91f7c54c45e39 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 20:40:06 +0000 Subject: [PATCH 09/23] add test --- test/fail/conv/Nat16.mo | 15 +++++++++++++++ test/fail/conv/Nat8.mo | 15 +++++++++++++++ test/fail/ok/suggest-conversion-ai.tc.ok | 17 +++++++++++++++++ test/fail/ok/suggest-conversion-ai.tc.ret.ok | 1 + test/fail/ok/suggest-conversion.tc.ok | 12 ++++++++++++ test/fail/ok/suggest-conversion.tc.ret.ok | 1 + test/fail/suggest-conversion-ai.mo | 10 ++++++++++ test/fail/suggest-conversion.mo | 10 ++++++++++ 8 files changed, 81 insertions(+) create mode 100644 test/fail/conv/Nat16.mo create mode 100644 test/fail/conv/Nat8.mo create mode 100644 test/fail/ok/suggest-conversion-ai.tc.ok create mode 100644 test/fail/ok/suggest-conversion-ai.tc.ret.ok create mode 100644 test/fail/ok/suggest-conversion.tc.ok create mode 100644 test/fail/ok/suggest-conversion.tc.ret.ok create mode 100644 test/fail/suggest-conversion-ai.mo create mode 100644 test/fail/suggest-conversion.mo diff --git a/test/fail/conv/Nat16.mo b/test/fail/conv/Nat16.mo new file mode 100644 index 00000000000..75b0c82354f --- /dev/null +++ b/test/fail/conv/Nat16.mo @@ -0,0 +1,15 @@ +import Prim "mo:⛔" +module { + + public func toNat(n : Nat16) : Nat { Prim.nat16ToNat(n) }; + + public func fromNat16(n : Nat16) : Nat { Prim.nat16ToNat(n) }; + + public module Outer { + public module Inner { + public func toNat(n : Nat16) : Nat { Prim.nat16ToNat(n) }; + public func fromNat16(n : Nat16) : Nat { Prim.nat16ToNat(n) }; + } + } + +} \ No newline at end of file diff --git a/test/fail/conv/Nat8.mo b/test/fail/conv/Nat8.mo new file mode 100644 index 00000000000..245bdaa4801 --- /dev/null +++ b/test/fail/conv/Nat8.mo @@ -0,0 +1,15 @@ +import Prim "mo:⛔" +module { + + public func toNat(n : Nat8) : Nat { Prim.nat8ToNat(n) }; + + public func fromNat8(n : Nat8) : Nat { Prim.nat8ToNat(n) }; + + public module Outer { + public module Inner { + public func toNat(n : Nat8) : Nat { Prim.nat8ToNat(n) }; + public func fromNat8(n : Nat8) : Nat { Prim.nat8ToNat(n) }; + } + } + +} \ No newline at end of file diff --git a/test/fail/ok/suggest-conversion-ai.tc.ok b/test/fail/ok/suggest-conversion-ai.tc.ok new file mode 100644 index 00000000000..b1982477810 --- /dev/null +++ b/test/fail/ok/suggest-conversion-ai.tc.ok @@ -0,0 +1,17 @@ +suggest-conversion-ai.mo:7.3-7.5: type error [M0096], expression of type + Nat8 +cannot produce expected type + Nat +suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.fromNat8(_)` +suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.toNat(_)` +suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.fromNat8(_)` +suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.toNat(_)` +suggest-conversion-ai.mo:8.3-8.6: type error [M0096], expression of type + Nat16 +cannot produce expected type + Nat +suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"` +suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` +suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"` +suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` +base conv filename conv/Nat16.mobase conv filename conv/Nat16.mo diff --git a/test/fail/ok/suggest-conversion-ai.tc.ret.ok b/test/fail/ok/suggest-conversion-ai.tc.ret.ok new file mode 100644 index 00000000000..69becfa16f9 --- /dev/null +++ b/test/fail/ok/suggest-conversion-ai.tc.ret.ok @@ -0,0 +1 @@ +Return code 1 diff --git a/test/fail/ok/suggest-conversion.tc.ok b/test/fail/ok/suggest-conversion.tc.ok new file mode 100644 index 00000000000..2ff4a8e0fbc --- /dev/null +++ b/test/fail/ok/suggest-conversion.tc.ok @@ -0,0 +1,12 @@ +suggest-conversion.mo:7.3-7.5: type error [M0096], expression of type + Nat8 +cannot produce expected type + Nat +suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.fromNat8(_)` +suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.toNat(_)` +suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.fromNat8(_)` +suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.toNat(_)` +suggest-conversion.mo:8.3-8.6: type error [M0096], expression of type + Nat16 +cannot produce expected type + Nat diff --git a/test/fail/ok/suggest-conversion.tc.ret.ok b/test/fail/ok/suggest-conversion.tc.ret.ok new file mode 100644 index 00000000000..69becfa16f9 --- /dev/null +++ b/test/fail/ok/suggest-conversion.tc.ret.ok @@ -0,0 +1 @@ +Return code 1 diff --git a/test/fail/suggest-conversion-ai.mo b/test/fail/suggest-conversion-ai.mo new file mode 100644 index 00000000000..e492dbe0b42 --- /dev/null +++ b/test/fail/suggest-conversion-ai.mo @@ -0,0 +1,10 @@ +//MOC-FLAG --package conv conv --ai-errors +// should report conversions from all available libs, even when not imported +import Nat8 = "mo:conv/Nat8" +func f(n : Nat) {}; +let n8 : Nat8 = 0; +let n16 : Nat16 = 0; +f(n8); +f(n16); + + diff --git a/test/fail/suggest-conversion.mo b/test/fail/suggest-conversion.mo new file mode 100644 index 00000000000..657f799f896 --- /dev/null +++ b/test/fail/suggest-conversion.mo @@ -0,0 +1,10 @@ +//MOC-FLAG --package conv conv +// should report conversions from all imported libs, not all available libs +import Nat8 = "mo:conv/Nat8" +func f(n : Nat) {}; +let n8 : Nat8 = 0; +let n16 : Nat16 = 0; +f(n8); +f(n16); + + From c5396a38bf972712b2b6d8a56ae0c7a58a2de4a5 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 20:41:43 +0000 Subject: [PATCH 10/23] typo --- src/pipeline/resolve_import.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pipeline/resolve_import.ml b/src/pipeline/resolve_import.ml index 5e768f3f8f8..aa349187e58 100644 --- a/src/pipeline/resolve_import.ml +++ b/src/pipeline/resolve_import.ml @@ -302,7 +302,7 @@ let resolve (List.fold_right (fun ri rim -> RIM.add ri Source.no_region rim) (package_imports base packages) RIM.empty) else - (* consder only the explicitly imported package libraries *) + (* consider only the explicitly imported package libraries *) RIM.empty) in List.iter (resolve_import_string msgs base actor_idl_path aliases packages imported)(prog_imports p); From bd2ceeac6a2501a25f59be76d2d469143d4f243c Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 20:52:21 +0000 Subject: [PATCH 11/23] formatting --- src/pipeline/resolve_import.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pipeline/resolve_import.ml b/src/pipeline/resolve_import.ml index aa349187e58..4307d134160 100644 --- a/src/pipeline/resolve_import.ml +++ b/src/pipeline/resolve_import.ml @@ -281,7 +281,6 @@ let package_imports base packages = in List.concat imports - let resolve_flags : flags -> resolved_flags Diag.result = fun { actor_idl_path; package_urls; actor_aliases; _ } -> let open Diag.Syntax in @@ -300,13 +299,13 @@ let resolve ref (if flags.include_all_libs then (* add all available package libraries *) (List.fold_right (fun ri rim -> RIM.add ri Source.no_region rim) - (package_imports base packages) RIM.empty) + (package_imports base packages) RIM.empty) else (* consider only the explicitly imported package libraries *) RIM.empty) in List.iter (resolve_import_string msgs base actor_idl_path aliases packages imported)(prog_imports p); - Some (List.map (fun (rim,at) -> rim @@ at) (RIM.bindings !imported)) + Some (List.map (fun (rim, at) -> rim @@ at) (RIM.bindings !imported)) ) From 3a22524b0db2b6202e493aaef1f59871aaaccd73 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 20:54:13 +0000 Subject: [PATCH 12/23] update output --- test/fail/ok/suggest-conversion-ai.tc.ok | 1 - 1 file changed, 1 deletion(-) diff --git a/test/fail/ok/suggest-conversion-ai.tc.ok b/test/fail/ok/suggest-conversion-ai.tc.ok index b1982477810..e331873d953 100644 --- a/test/fail/ok/suggest-conversion-ai.tc.ok +++ b/test/fail/ok/suggest-conversion-ai.tc.ok @@ -14,4 +14,3 @@ suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner. suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"` suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` -base conv filename conv/Nat16.mobase conv filename conv/Nat16.mo From dbf67632bc659fff578133143772dc1fd385c8b2 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 21:55:13 +0000 Subject: [PATCH 13/23] refactor --- src/mo_frontend/typing.ml | 121 +++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index a6e2189a56f..66be93a677b 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -325,55 +325,61 @@ type lib_sort = Imported of string | NonImported of {id : string; package : stri let suggest_conversion env at ty1 ty2 = T.(match promote ty1, promote ty2 with | Prim p1, Prim p2 -> - let rec search_obj lib_sort path ty = - match T.promote ty with - | T.Obj(_, tfs) -> - tfs |> - List.iter (fun {lab;typ;_} -> - match T.normalize typ with - | T.Func _ when - (Lib.String.starts_with "to" lab || - Lib.String.starts_with "from" lab) && - T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> - (match lib_sort with - | Imported id -> - info env at - "maybe try conversion `%s.%s%s(_)`" - id path lab - | NonImported {id; package; rel_name} -> - info env at - "maybe try conversion `%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" - id path lab id package rel_name) - | T.Obj(_, tfs) as ty1 -> - search_obj lib_sort (path^lab^".") ty1 - | _ -> ()) - | _ -> () - in - T.Env.iter (fun filename ty -> - if Lib.String.starts_with "@" filename - then () (* skip prim etc *) - else - let imported_name = T.Env.fold (fun id (ty1, _, _, _) acc -> - if ty == ty1 then Some id else acc) env.vals None - in - let lib_sort_opt = match imported_name with - | Some id -> Some (Imported id) - | None -> - Flags.M.fold (fun package path acc -> - let base = Lib.FilePath.normalise path in - match Lib.FilePath.relative_to base filename with - | None -> acc - | Some rel_path -> - let rel_name = Filename.chop_extension rel_path in - let id = Filename.basename rel_name in + let suggestions = ref [] in + let rec search_obj lib_sort path ty = + match T.promote ty with + | T.Obj(_, tfs) -> + tfs |> + List.iter (fun {lab;typ;_} -> + match T.normalize typ with + | T.Func _ when + (Lib.String.starts_with "to" lab || + Lib.String.starts_with "from" lab) && + T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> + (match lib_sort with + | Imported id -> + suggestions := Printf.sprintf "`%s.%s%s(_)`" id path lab :: !suggestions + | NonImported {id; package; rel_name} -> + suggestions := + Printf.sprintf "`%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" + id path lab id package rel_name :: !suggestions) + | T.Obj(_, tfs) as ty1 -> + search_obj lib_sort (path^lab^".") ty1 + | _ -> ()) + | _ -> () + in + T.Env.iter (fun filename ty -> + if Lib.String.starts_with "@" filename + then () (* skip prim etc *) + else + let imported_name = T.Env.fold (fun id (ty1, _, _, _) acc -> + if ty == ty1 then Some id else acc) env.vals None + in + let lib_sort_opt = match imported_name with + | Some id -> Some (Imported id) + | None -> + Flags.M.fold (fun package path acc -> + let base = Lib.FilePath.normalise path in + match Lib.FilePath.relative_to base filename with + | None -> acc + | Some rel_path -> + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in Some (NonImported {id; package; rel_name})) - (!Flags.package_urls) None - in - match lib_sort_opt with - | None -> () - | Some lib_sort -> search_obj lib_sort "" ty) - env.libs - | _ -> ()) + (!Flags.package_urls) None + in + match lib_sort_opt with + | None -> () + | Some lib_sort -> search_obj lib_sort "" ty) + env.libs; + if !suggestions = [] + then "" + else + let rest, last = Lib.List.split_last !suggestions in + Printf.sprintf "\nmaybe try conversion:\n %s?" + ((if rest <> [] then (String.concat ",\n " rest) ^ " or\n " else "") ^ last) + (* not primitive types, make no suggestion *) + | _, _ -> "") (* Value environments *) @@ -1214,14 +1220,11 @@ let check_lit env t lit at suggest = | t, _ -> let t' = T.Prim (infer_lit env lit at) in if not (T.sub t' t) then - begin - (if suggest then local_error else error) - env at "M0050" - "literal of type%a\ndoes not have expected type%a" - display_typ t' - display_typ_expand t; - if suggest then suggest_conversion env at t' t - end + error env at "M0050" + "literal of type%a\ndoes not have expected type%a%s" + display_typ t' + display_typ_expand t + (if suggest then suggest_conversion env at t' t else "") (* Coercions *) @@ -2056,10 +2059,10 @@ and check_exp' env0 t exp : T.typ = if not (T.sub t' t) then begin local_error env0 exp.at "M0096" - "expression of type%a\ncannot produce expected type%a" + "expression of type%a\ncannot produce expected type%a%s" display_typ_expand t' - display_typ_expand t; - suggest_conversion env0 exp.at t' t + display_typ_expand t + (suggest_conversion env0 exp.at t' t) end; t' From ac077316b47a44c198cc569d6cab7b000fe42e20 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 21:55:40 +0000 Subject: [PATCH 14/23] update output --- test/fail/ok/suggest-conversion-ai.tc.ok | 18 ++++++++++-------- test/fail/ok/suggest-conversion.tc.ok | 9 +++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/test/fail/ok/suggest-conversion-ai.tc.ok b/test/fail/ok/suggest-conversion-ai.tc.ok index e331873d953..ac1cbe90c6d 100644 --- a/test/fail/ok/suggest-conversion-ai.tc.ok +++ b/test/fail/ok/suggest-conversion-ai.tc.ok @@ -2,15 +2,17 @@ suggest-conversion-ai.mo:7.3-7.5: type error [M0096], expression of type Nat8 cannot produce expected type Nat -suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.fromNat8(_)` -suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.toNat(_)` -suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.fromNat8(_)` -suggest-conversion-ai.mo:7.3-7.5: info, maybe try conversion `Nat8.toNat(_)` +maybe try conversion: + `Nat8.toNat(_)`, + `Nat8.fromNat8(_)`, + `Nat8.Outer.Inner.toNat(_)` or + `Nat8.Outer.Inner.fromNat8(_)`? suggest-conversion-ai.mo:8.3-8.6: type error [M0096], expression of type Nat16 cannot produce expected type Nat -suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"` -suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.Outer.Inner.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` -suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"` -suggest-conversion-ai.mo:8.3-8.6: info, maybe try conversion `Nat16.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` +maybe try conversion: + `Nat16.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"`, + `Nat16.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"`, + `Nat16.Outer.Inner.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` or + `Nat16.Outer.Inner.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"`? diff --git a/test/fail/ok/suggest-conversion.tc.ok b/test/fail/ok/suggest-conversion.tc.ok index 2ff4a8e0fbc..329ad768642 100644 --- a/test/fail/ok/suggest-conversion.tc.ok +++ b/test/fail/ok/suggest-conversion.tc.ok @@ -2,10 +2,11 @@ suggest-conversion.mo:7.3-7.5: type error [M0096], expression of type Nat8 cannot produce expected type Nat -suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.fromNat8(_)` -suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.Outer.Inner.toNat(_)` -suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.fromNat8(_)` -suggest-conversion.mo:7.3-7.5: info, maybe try conversion `Nat8.toNat(_)` +maybe try conversion: + `Nat8.toNat(_)`, + `Nat8.fromNat8(_)`, + `Nat8.Outer.Inner.toNat(_)` or + `Nat8.Outer.Inner.fromNat8(_)`? suggest-conversion.mo:8.3-8.6: type error [M0096], expression of type Nat16 cannot produce expected type From 1dcfd33d66349af54407bfd5249301f1f33ebdf5 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 21:56:35 +0000 Subject: [PATCH 15/23] restore test output --- test/fail/ok/one-tuple-ambiguity.tc.ok | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/fail/ok/one-tuple-ambiguity.tc.ok b/test/fail/ok/one-tuple-ambiguity.tc.ok index 238650a2ca4..f0810e0998e 100644 --- a/test/fail/ok/one-tuple-ambiguity.tc.ok +++ b/test/fail/ok/one-tuple-ambiguity.tc.ok @@ -2,6 +2,3 @@ one-tuple-ambiguity.mo:16.3-16.5: type error [M0050], literal of type Nat does not have expected type (Nat, Bool) -one-tuple-ambiguity.mo:16.1-16.5: type error [M0097], expected function type, but expression produces type - () -one-tuple-ambiguity.mo:16.5-16.6: info, this looks like an unintended function call, perhaps a missing ';'? From 043720eef17c3a4519a2301336b014ec2f500c15 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 21:59:09 +0000 Subject: [PATCH 16/23] Update test/fail/conv/Nat16.mo --- test/fail/conv/Nat16.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fail/conv/Nat16.mo b/test/fail/conv/Nat16.mo index 75b0c82354f..7f78a828c31 100644 --- a/test/fail/conv/Nat16.mo +++ b/test/fail/conv/Nat16.mo @@ -12,4 +12,4 @@ module { } } -} \ No newline at end of file +} From 6fdccd3d501ba9afdf145722f0b331b0bf89f0fd Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 21:59:24 +0000 Subject: [PATCH 17/23] Update test/fail/conv/Nat8.mo --- test/fail/conv/Nat8.mo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fail/conv/Nat8.mo b/test/fail/conv/Nat8.mo index 245bdaa4801..29ddb8dfd1c 100644 --- a/test/fail/conv/Nat8.mo +++ b/test/fail/conv/Nat8.mo @@ -12,4 +12,4 @@ module { } } -} \ No newline at end of file +} From 13a1b82ced33fc088451419ba2c4954face673ad Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 22:04:17 +0000 Subject: [PATCH 18/23] adjust formatting --- src/mo_frontend/typing.ml | 2 +- test/fail/ok/suggest-conversion-ai.tc.ok | 4 ++-- test/fail/ok/suggest-conversion.tc.ok | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 66be93a677b..56c8cb1aa69 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -376,7 +376,7 @@ let suggest_conversion env at ty1 ty2 = then "" else let rest, last = Lib.List.split_last !suggestions in - Printf.sprintf "\nmaybe try conversion:\n %s?" + Printf.sprintf "\nMaybe try conversion:\n %s?" ((if rest <> [] then (String.concat ",\n " rest) ^ " or\n " else "") ^ last) (* not primitive types, make no suggestion *) | _, _ -> "") diff --git a/test/fail/ok/suggest-conversion-ai.tc.ok b/test/fail/ok/suggest-conversion-ai.tc.ok index ac1cbe90c6d..664fea6a202 100644 --- a/test/fail/ok/suggest-conversion-ai.tc.ok +++ b/test/fail/ok/suggest-conversion-ai.tc.ok @@ -2,7 +2,7 @@ suggest-conversion-ai.mo:7.3-7.5: type error [M0096], expression of type Nat8 cannot produce expected type Nat -maybe try conversion: +Maybe try conversion: `Nat8.toNat(_)`, `Nat8.fromNat8(_)`, `Nat8.Outer.Inner.toNat(_)` or @@ -11,7 +11,7 @@ suggest-conversion-ai.mo:8.3-8.6: type error [M0096], expression of type Nat16 cannot produce expected type Nat -maybe try conversion: +Maybe try conversion: `Nat16.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"`, `Nat16.fromNat16(_)` after adding `import Nat16 = "mo:conv/Nat16"`, `Nat16.Outer.Inner.toNat(_)` after adding `import Nat16 = "mo:conv/Nat16"` or diff --git a/test/fail/ok/suggest-conversion.tc.ok b/test/fail/ok/suggest-conversion.tc.ok index 329ad768642..2bd5a0604bb 100644 --- a/test/fail/ok/suggest-conversion.tc.ok +++ b/test/fail/ok/suggest-conversion.tc.ok @@ -2,7 +2,7 @@ suggest-conversion.mo:7.3-7.5: type error [M0096], expression of type Nat8 cannot produce expected type Nat -maybe try conversion: +Maybe try conversion: `Nat8.toNat(_)`, `Nat8.fromNat8(_)`, `Nat8.Outer.Inner.toNat(_)` or From b913654cc917e7ea7d7afe50e42b2d8b8526f861 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Wed, 30 Oct 2024 22:06:28 +0000 Subject: [PATCH 19/23] ocamlformat --- src/languageServer/declaration_index.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languageServer/declaration_index.ml b/src/languageServer/declaration_index.ml index ea54c609524..fcc9b865e81 100644 --- a/src/languageServer/declaration_index.ml +++ b/src/languageServer/declaration_index.ml @@ -188,7 +188,7 @@ let empty : string -> t = package_urls = !Flags.package_urls; actor_aliases = !Flags.actor_aliases; actor_idl_path = !Flags.actor_idl_path; - include_all_libs = false (* TBR *) + include_all_libs = false (* TBR *); }) in { From f4c95dcec29ac56bd64adf5758592aa8761dd5e9 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 31 Oct 2024 14:46:06 +0000 Subject: [PATCH 20/23] refactor and simplify code --- src/mo_frontend/typing.ml | 145 +++++++++++++++++++++----------------- 1 file changed, 79 insertions(+), 66 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 56c8cb1aa69..146b2fedc3d 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -296,6 +296,10 @@ let leave_scope env inner_identifiers initial_usage = (* Suggestions *) +let oneof sep lastsep ss = + let rest, last = Lib.List.split_last ss in + ((if rest <> [] then (String.concat sep rest) ^ lastsep else "") ^ last) + let suggest desc id ids = if !Flags.ai_errors then Printf.sprintf @@ -315,71 +319,80 @@ let suggest desc id ids = in if suggestions = [] then "" else - let rest, last = Lib.List.split_last suggestions in - Printf.sprintf "\nDid you mean %s %s?" - desc - ((if rest <> [] then (String.concat ", " rest) ^ " or " else "") ^ last) - - -type lib_sort = Imported of string | NonImported of {id : string; package : string; rel_name : string } -let suggest_conversion env at ty1 ty2 = - T.(match promote ty1, promote ty2 with - | Prim p1, Prim p2 -> - let suggestions = ref [] in - let rec search_obj lib_sort path ty = - match T.promote ty with - | T.Obj(_, tfs) -> - tfs |> - List.iter (fun {lab;typ;_} -> - match T.normalize typ with - | T.Func _ when - (Lib.String.starts_with "to" lab || - Lib.String.starts_with "from" lab) && - T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> - (match lib_sort with - | Imported id -> - suggestions := Printf.sprintf "`%s.%s%s(_)`" id path lab :: !suggestions - | NonImported {id; package; rel_name} -> - suggestions := - Printf.sprintf "`%s.%s%s(_)` after adding `import %s = \"mo:%s/%s\"`" - id path lab id package rel_name :: !suggestions) - | T.Obj(_, tfs) as ty1 -> - search_obj lib_sort (path^lab^".") ty1 - | _ -> ()) - | _ -> () - in - T.Env.iter (fun filename ty -> - if Lib.String.starts_with "@" filename - then () (* skip prim etc *) - else - let imported_name = T.Env.fold (fun id (ty1, _, _, _) acc -> - if ty == ty1 then Some id else acc) env.vals None - in - let lib_sort_opt = match imported_name with - | Some id -> Some (Imported id) - | None -> - Flags.M.fold (fun package path acc -> - let base = Lib.FilePath.normalise path in - match Lib.FilePath.relative_to base filename with - | None -> acc - | Some rel_path -> - let rel_name = Filename.chop_extension rel_path in - let id = Filename.basename rel_name in - Some (NonImported {id; package; rel_name})) - (!Flags.package_urls) None - in - match lib_sort_opt with - | None -> () - | Some lib_sort -> search_obj lib_sort "" ty) - env.libs; - if !suggestions = [] - then "" - else - let rest, last = Lib.List.split_last !suggestions in - Printf.sprintf "\nMaybe try conversion:\n %s?" - ((if rest <> [] then (String.concat ",\n " rest) ^ " or\n " else "") ^ last) + Printf.sprintf "\nDid you mean %s %s?" desc (oneof ", " " or " suggestions) + +let search_obj desc path ty ty1 ty2 = + let open T in + let suggestions = ref [] in + let seen = ref S.empty in + let rec go path ty = + if S.mem ty !seen then () + else begin + seen := S.add ty (!seen); + match promote ty with + | Obj(_, tfs) -> + tfs |> + List.iter (fun {lab;typ;_} -> + match normalize typ with + | T.Func _ when + (Lib.String.starts_with "to" lab || + Lib.String.starts_with "from" lab) && + T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> + suggestions := Printf.sprintf "`%s.%s(_)`%s" path lab desc :: !suggestions + | Obj(_, tfs) as ty1 -> + go (path^"."^lab) ty1 + | _ -> ()) + | _ -> () + end + in + go path ty; + !suggestions + +let suggest_conversion libs vals ty1 ty2 = + let open T in + match promote ty1, promote ty2 with + | Prim p1, Prim p2 -> + let suggestions = ref [] in + T.Env.iter (fun filename ty -> + if Lib.String.starts_with "@" filename + then () (* skip prim etc *) + else + let imported_name = + (* try to determine imported name, if any *) + T.Env.fold (fun id (ty1, _, _, _) acc -> + if ty == ty1 (*HACK*) + then Some id + else acc) + vals None + in + let lib_opt = match imported_name with + | Some id -> Some (id, "") + | None -> + (* search libs for suggested import *) + Flags.M.fold (fun package path acc -> + let base = Lib.FilePath.normalise path in + match Lib.FilePath.relative_to base filename with + | None -> acc + | Some rel_path -> + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in + Some ( + id, + Printf.sprintf " after adding `import %s = \"mo:%s/%s\"`" id package rel_name)) + !Flags.package_urls None + in + match lib_opt with + | None -> () + | Some (id, desc) -> + suggestions := (search_obj desc id ty ty1 ty2) @ !suggestions) + libs; + if !suggestions = [] + then "" + else + Printf.sprintf "\nMaybe try conversion:\n %s?" + (oneof ",\n " " or\n " !suggestions) (* not primitive types, make no suggestion *) - | _, _ -> "") + | _, _ -> "" (* Value environments *) @@ -1224,7 +1237,7 @@ let check_lit env t lit at suggest = "literal of type%a\ndoes not have expected type%a%s" display_typ t' display_typ_expand t - (if suggest then suggest_conversion env at t' t else "") + (if suggest then suggest_conversion env.libs env.vals t' t else "") (* Coercions *) @@ -2062,7 +2075,7 @@ and check_exp' env0 t exp : T.typ = "expression of type%a\ncannot produce expected type%a%s" display_typ_expand t' display_typ_expand t - (suggest_conversion env0 exp.at t' t) + (suggest_conversion env.libs env.vals t' t) end; t' From 73914064d17e27c8545b4e92ea6e22b4ed887475 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 31 Oct 2024 15:36:28 +0000 Subject: [PATCH 21/23] move suggestion logic into suggest.ml --- src/mo_frontend/suggest.ml | 102 ++++++++++++++++++++++++++++++++++++ src/mo_frontend/suggest.mli | 5 ++ 2 files changed, 107 insertions(+) create mode 100644 src/mo_frontend/suggest.ml create mode 100644 src/mo_frontend/suggest.mli diff --git a/src/mo_frontend/suggest.ml b/src/mo_frontend/suggest.ml new file mode 100644 index 00000000000..3b82447e8ae --- /dev/null +++ b/src/mo_frontend/suggest.ml @@ -0,0 +1,102 @@ + +(* Suggestions *) +open Mo_types +open Mo_config +open Type + +let oneof sep lastsep ss = + let rest, last = Lib.List.split_last ss in + ((if rest <> [] then (String.concat sep rest) ^ lastsep else "") ^ last) + +let suggest_id desc id ids = + if !Flags.ai_errors then + Printf.sprintf + "\nThe %s %s is not available. Try something else?" + desc + id + else + let suggestions = + let limit = Lib.Int.log2 (String.length id) in + let distance = Lib.String.levenshtein_distance id in + let weighted_ids = List.filter_map (fun id0 -> + let d = distance id0 in + if Lib.String.starts_with id id0 || d <= limit then + Some (d, id0) + else None) ids in + List.sort compare weighted_ids |> List.map snd + in + if suggestions = [] then "" + else + Printf.sprintf "\nDid you mean %s %s?" desc (oneof ", " " or " suggestions) + +let search_obj desc path ty ty1 ty2 = + let suggestions = ref [] in + let seen = ref S.empty in + let rec go path ty = + if S.mem ty !seen then () + else begin + seen := S.add ty (!seen); + match promote ty with + | Obj(_, tfs) -> + tfs |> + List.iter (fun {lab;typ;_} -> + match normalize typ with + | Func _ when + (Lib.String.starts_with "to" lab || + Lib.String.starts_with "from" lab) && + sub typ (Func(Local, Returns, [], [ty1], [ty2])) -> + suggestions := Printf.sprintf "`%s.%s(_)`%s" path lab desc :: !suggestions + | Obj(_, tfs) as ty1 -> + go (path^"."^lab) ty1 + | _ -> ()) + | _ -> () + end + in + go path ty; + !suggestions + +let suggest_conversion libs vals ty1 ty2 = + match promote ty1, promote ty2 with + | Prim p1, Prim p2 -> + let suggestions = ref [] in + Env.iter (fun filename ty -> + if Lib.String.starts_with "@" filename + then () (* skip prim etc *) + else + let imported_name = + (* try to determine imported name, if any *) + Env.fold (fun id (ty1, _, _, _) acc -> + if ty == ty1 (*HACK*) + then Some id + else acc) + vals None + in + let lib_opt = match imported_name with + | Some id -> Some (id, "") + | None -> + (* search libs for suggested import *) + Flags.M.fold (fun package path acc -> + let base = Lib.FilePath.normalise path in + match Lib.FilePath.relative_to base filename with + | None -> acc + | Some rel_path -> + let rel_name = Filename.chop_extension rel_path in + let id = Filename.basename rel_name in + Some ( + id, + Printf.sprintf " after adding `import %s = \"mo:%s/%s\"`" id package rel_name)) + !Flags.package_urls None + in + match lib_opt with + | None -> () + | Some (id, desc) -> + suggestions := (search_obj desc id ty ty1 ty2) @ !suggestions) + libs; + if !suggestions = [] + then "" + else + Printf.sprintf "\nMaybe try conversion:\n %s?" + (oneof ",\n " " or\n " !suggestions) + (* not primitive types, make no suggestion *) + | _, _ -> "" + diff --git a/src/mo_frontend/suggest.mli b/src/mo_frontend/suggest.mli new file mode 100644 index 00000000000..ed3bcede043 --- /dev/null +++ b/src/mo_frontend/suggest.mli @@ -0,0 +1,5 @@ +open Mo_types + +val suggest_id : string (* desc *) -> string (* id *) -> string list (* ids *) -> string + +val suggest_conversion : Scope.lib_env -> (Type.typ * _ * _ * _) Type.Env.t -> Type.typ -> Type.typ -> string From d7eff7b328c9fbf765c77d5618812f6e7a2bbad3 Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 31 Oct 2024 15:36:53 +0000 Subject: [PATCH 22/23] move suggestion logic into suggest.ml --- src/mo_frontend/typing.ml | 118 +++----------------------------------- 1 file changed, 9 insertions(+), 109 deletions(-) diff --git a/src/mo_frontend/typing.ml b/src/mo_frontend/typing.ml index 146b2fedc3d..632f51eb92d 100644 --- a/src/mo_frontend/typing.ml +++ b/src/mo_frontend/typing.ml @@ -294,106 +294,6 @@ let leave_scope env inner_identifiers initial_usage = let final_usage = S.union initial_usage unshadowed_usage in env.used_identifiers := final_usage -(* Suggestions *) - -let oneof sep lastsep ss = - let rest, last = Lib.List.split_last ss in - ((if rest <> [] then (String.concat sep rest) ^ lastsep else "") ^ last) - -let suggest desc id ids = - if !Flags.ai_errors then - Printf.sprintf - "\nThe %s %s is not available. Try something else?" - desc - id - else - let suggestions = - let limit = Lib.Int.log2 (String.length id) in - let distance = Lib.String.levenshtein_distance id in - let weighted_ids = List.filter_map (fun id0 -> - let d = distance id0 in - if Lib.String.starts_with id id0 || d <= limit then - Some (d, id0) - else None) ids in - List.sort compare weighted_ids |> List.map snd - in - if suggestions = [] then "" - else - Printf.sprintf "\nDid you mean %s %s?" desc (oneof ", " " or " suggestions) - -let search_obj desc path ty ty1 ty2 = - let open T in - let suggestions = ref [] in - let seen = ref S.empty in - let rec go path ty = - if S.mem ty !seen then () - else begin - seen := S.add ty (!seen); - match promote ty with - | Obj(_, tfs) -> - tfs |> - List.iter (fun {lab;typ;_} -> - match normalize typ with - | T.Func _ when - (Lib.String.starts_with "to" lab || - Lib.String.starts_with "from" lab) && - T.sub typ (T.Func(T.Local, T.Returns, [], [ty1], [ty2])) -> - suggestions := Printf.sprintf "`%s.%s(_)`%s" path lab desc :: !suggestions - | Obj(_, tfs) as ty1 -> - go (path^"."^lab) ty1 - | _ -> ()) - | _ -> () - end - in - go path ty; - !suggestions - -let suggest_conversion libs vals ty1 ty2 = - let open T in - match promote ty1, promote ty2 with - | Prim p1, Prim p2 -> - let suggestions = ref [] in - T.Env.iter (fun filename ty -> - if Lib.String.starts_with "@" filename - then () (* skip prim etc *) - else - let imported_name = - (* try to determine imported name, if any *) - T.Env.fold (fun id (ty1, _, _, _) acc -> - if ty == ty1 (*HACK*) - then Some id - else acc) - vals None - in - let lib_opt = match imported_name with - | Some id -> Some (id, "") - | None -> - (* search libs for suggested import *) - Flags.M.fold (fun package path acc -> - let base = Lib.FilePath.normalise path in - match Lib.FilePath.relative_to base filename with - | None -> acc - | Some rel_path -> - let rel_name = Filename.chop_extension rel_path in - let id = Filename.basename rel_name in - Some ( - id, - Printf.sprintf " after adding `import %s = \"mo:%s/%s\"`" id package rel_name)) - !Flags.package_urls None - in - match lib_opt with - | None -> () - | Some (id, desc) -> - suggestions := (search_obj desc id ty ty1 ty2) @ !suggestions) - libs; - if !suggestions = [] - then "" - else - Printf.sprintf "\nMaybe try conversion:\n %s?" - (oneof ",\n " " or\n " !suggestions) - (* not primitive types, make no suggestion *) - | _, _ -> "" - (* Value environments *) let singleton id t = T.Env.singleton id.it (t, id.at, Scope.Declaration) @@ -554,7 +454,7 @@ and check_obj_path' env path : T.typ = | None -> error env id.at "M0026" "unbound variable %s%a%s" id.it display_vals env.vals - (suggest "variable" id.it (T.Env.keys env.vals)) + (Suggest.suggest_id "variable" id.it (T.Env.keys env.vals)) ) | DotH (path', id) -> let s, fs = check_obj_path env path' in @@ -566,7 +466,7 @@ and check_obj_path' env path : T.typ = error env id.at "M0028" "field %s does not exist in %a%s" id.it display_obj (s, fs) - (suggest "field" id.it + (Suggest.suggest_id "field" id.it (List.filter_map (function {T.typ=T.Typ _;_} -> None @@ -586,7 +486,7 @@ and check_typ_path' env path : T.con = | None -> error env id.at "M0029" "unbound type %s%a%s" id.it display_typs env.typs - (suggest "type" id.it (T.Env.keys env.typs)) + (Suggest.suggest_id "type" id.it (T.Env.keys env.typs)) ) | DotH (path', id) -> let s, fs = check_obj_path env path' in @@ -597,7 +497,7 @@ and check_typ_path' env path : T.con = | exception Invalid_argument _ -> error env id.at "M0030" "type field %s does not exist in type%a%s" id.it display_typ_expand (T.Obj (s, fs)) - (suggest "type field" id.it + (Suggest.suggest_id "type field" id.it (List.filter_map (function { T.lab; T.typ=T.Typ _;_ } -> Some lab | _ -> None) fs)) @@ -1237,7 +1137,7 @@ let check_lit env t lit at suggest = "literal of type%a\ndoes not have expected type%a%s" display_typ t' display_typ_expand t - (if suggest then suggest_conversion env.libs env.vals t' t else "") + (if suggest then Suggest.suggest_conversion env.libs env.vals t' t else "") (* Coercions *) @@ -1329,7 +1229,7 @@ and infer_exp'' env exp : T.typ = | None -> error env id.at "M0057" "unbound variable %s%a%s" id.it display_vals env.vals - (suggest "variable" id.it (T.Env.keys env.vals)) + (Suggest.suggest_id "variable" id.it (T.Env.keys env.vals)) ) | LitE lit -> T.Prim (infer_lit env lit exp.at) @@ -1568,7 +1468,7 @@ and infer_exp'' env exp : T.typ = "field %s does not exist in %a%s" id.it display_obj (s, tfs) - (suggest "field" id.it + (Suggest.suggest_id "field" id.it (List.filter_map (function { T.typ=T.Typ _;_} -> None @@ -1772,7 +1672,7 @@ and infer_exp'' env exp : T.typ = | _ -> id.it in local_error env id.at "M0083" "unbound label %s%a%s" name display_labs env.labs - (suggest "label" id.it (T.Env.keys env.labs)) + (Suggest.suggest_id "label" id.it (T.Env.keys env.labs)) ); T.Non | RetE exp1 -> @@ -2075,7 +1975,7 @@ and check_exp' env0 t exp : T.typ = "expression of type%a\ncannot produce expected type%a%s" display_typ_expand t' display_typ_expand t - (suggest_conversion env.libs env.vals t' t) + (Suggest.suggest_conversion env.libs env.vals t' t) end; t' From 635b285bedd6eb5bb4fe2308fb4701679910b89b Mon Sep 17 00:00:00 2001 From: Claudio Russo Date: Thu, 31 Oct 2024 16:04:17 +0000 Subject: [PATCH 23/23] Update src/mo_frontend/suggest.ml --- src/mo_frontend/suggest.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mo_frontend/suggest.ml b/src/mo_frontend/suggest.ml index 3b82447e8ae..cd4c1dbaff6 100644 --- a/src/mo_frontend/suggest.ml +++ b/src/mo_frontend/suggest.ml @@ -83,8 +83,8 @@ let suggest_conversion libs vals ty1 ty2 = let rel_name = Filename.chop_extension rel_path in let id = Filename.basename rel_name in Some ( - id, - Printf.sprintf " after adding `import %s = \"mo:%s/%s\"`" id package rel_name)) + id, + Printf.sprintf " after adding `import %s = \"mo:%s/%s\"`" id package rel_name)) !Flags.package_urls None in match lib_opt with