-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow defining libs with same name in multiple contexts #10179
Changes from 11 commits
86011bc
5704dbc
9e0fa23
55378f3
845ac40
d0a26c2
15dd99c
a17622a
803a6fe
b970f3c
91da01d
c97b26f
ec4dd8f
583255c
f922540
f01cee4
81381b7
44eb127
d333475
531e4d3
1a3558a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -132,6 +132,18 @@ module Error = struct | |
] | ||
;; | ||
|
||
let duplicated ~loc ~name ~dir_a ~dir_b = | ||
User_error.make | ||
~loc | ||
[ Pp.textf | ||
"A library with name %S is defined in two folders: %s and %s. Either change \ | ||
one of the names, or enable them conditionally using the 'enabled_if' field." | ||
(Lib_name.to_string name) | ||
(Path.to_string_maybe_quoted dir_a) | ||
(Path.to_string_maybe_quoted dir_b) | ||
] | ||
;; | ||
|
||
(* diml: it is not very clear what a "default implementation cycle" is *) | ||
let default_implementation_cycle cycle = | ||
make | ||
|
@@ -406,12 +418,13 @@ type db = | |
|
||
and resolve_result = | ||
| Not_found | ||
| Found of Lib_info.external_ | ||
| Found of Lib_info.external_ list | ||
| Hidden of Lib_info.external_ Hidden.t | ||
| Invalid of User_message.t | ||
| Ignore | ||
| Redirect_in_the_same_db of (Loc.t * Lib_name.t) | ||
| Redirect_in_the_same_db of (Loc.t * Lib_name.t) list | ||
| Redirect of db * (Loc.t * Lib_name.t) | ||
| Deprecated_library_name of (Loc.t * Lib_name.t) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding a new variant to distinguish between a regular redirect (public libs) and deprecated libs. Treating them both the same way leads to all the tests in |
||
|
||
let lib_config (t : lib) = t.lib_config | ||
let name t = t.name | ||
|
@@ -1130,19 +1143,75 @@ end = struct | |
| Hidden h -> Hidden.error h ~loc ~name >>| Option.some | ||
;; | ||
|
||
let find_in_parent ~db ~name = | ||
let open Memo.O in | ||
let+ res = | ||
match db.parent with | ||
| None -> Memo.return Status.Not_found | ||
| Some db -> find_internal db name | ||
in | ||
res | ||
;; | ||
|
||
let to_status ~db ~name = function | ||
| [] -> find_in_parent ~db ~name | ||
| info :: [] -> instantiate db name info ~hidden:None | ||
| a :: b :: _ -> | ||
let loc = Lib_info.loc b in | ||
let dir_a = Lib_info.src_dir a in | ||
let dir_b = Lib_info.src_dir b in | ||
Memo.return (Status.Invalid (Error.duplicated ~loc ~name ~dir_a ~dir_b)) | ||
;; | ||
|
||
let resolve_name db name = | ||
let open Memo.O in | ||
db.resolve name | ||
>>= function | ||
| Ignore -> Memo.return Status.Ignore | ||
| Redirect_in_the_same_db (_, name') -> find_internal db name' | ||
| Deprecated_library_name (_, name') -> find_internal db name' | ||
| Redirect_in_the_same_db redirects -> | ||
let result = List.map ~f:(fun (_, name') -> find_internal db name') redirects in | ||
let* statuses = | ||
Memo.List.map result ~f:(fun redirect -> | ||
let* r = redirect in | ||
Memo.return r) | ||
in | ||
Memo.return | ||
(List.fold_left statuses ~init:Status.Not_found ~f:(fun acc status -> | ||
match acc, status with | ||
| Status.Found a, Status.Found b -> | ||
let a = info a in | ||
let b = info b in | ||
let loc = Lib_info.loc b in | ||
let dir_a = Lib_info.src_dir a in | ||
let dir_b = Lib_info.src_dir b in | ||
Status.Invalid (Error.duplicated ~loc ~name ~dir_a ~dir_b) | ||
| Invalid _, _ -> acc | ||
| (Found _ as lib), (Hidden _ | Ignore | Not_found | Invalid _) | ||
| (Hidden _ | Ignore | Not_found), (Found _ as lib) -> lib | ||
| (Hidden _ | Ignore | Not_found), (Hidden _ | Ignore | Not_found | Invalid _) | ||
-> acc)) | ||
| Redirect (db', (_, name')) -> find_internal db' name' | ||
| Found info -> instantiate db name info ~hidden:None | ||
| Found libs -> | ||
(match libs with | ||
| [] | _ :: [] -> | ||
(* In case we have 0 or 1 results found, convert to [Status.t] directly. | ||
This allows to provide better errors later on, | ||
e.g. `Library "foo" in _build/default is hidden (unsatisfied 'enabled_if') *) | ||
to_status ~db ~name libs | ||
| _ :: _ :: _ -> | ||
(* If there are multiple results found, we optimistically pre-filter to | ||
remove those that are disabled *) | ||
let* filtered_libs = | ||
Memo.List.filter libs ~f:(fun lib -> | ||
let+ enabled = Lib_info.enabled lib in | ||
match enabled with | ||
| Disabled_because_of_enabled_if -> false | ||
| Normal | Optional -> true) | ||
in | ||
to_status ~db ~name filtered_libs) | ||
| Invalid e -> Memo.return (Status.Invalid e) | ||
| Not_found -> | ||
(match db.parent with | ||
| None -> Memo.return Status.Not_found | ||
| Some db -> find_internal db name) | ||
| Not_found -> find_in_parent ~db ~name | ||
| Hidden { lib = info; reason = hidden; path = _ } -> | ||
(match db.parent with | ||
| None -> Memo.return Status.Not_found | ||
|
@@ -1774,29 +1843,35 @@ module DB = struct | |
module Resolve_result = struct | ||
type t = resolve_result = | ||
| Not_found | ||
| Found of Lib_info.external_ | ||
| Found of Lib_info.external_ list | ||
| Hidden of Lib_info.external_ Hidden.t | ||
| Invalid of User_message.t | ||
| Ignore | ||
| Redirect_in_the_same_db of (Loc.t * Lib_name.t) | ||
| Redirect_in_the_same_db of (Loc.t * Lib_name.t) list | ||
| Redirect of db * (Loc.t * Lib_name.t) | ||
| Deprecated_library_name of (Loc.t * Lib_name.t) | ||
|
||
let found f = Found f | ||
let not_found = Not_found | ||
let redirect db lib = Redirect (db, lib) | ||
let redirect_in_the_same_db lib = Redirect_in_the_same_db lib | ||
let redirect_in_the_same_db libs = Redirect_in_the_same_db libs | ||
let deprecated_library_name lib = Deprecated_library_name lib | ||
|
||
let to_dyn x = | ||
let open Dyn in | ||
match x with | ||
| Not_found -> variant "Not_found" [] | ||
| Invalid e -> variant "Invalid" [ Dyn.string (User_message.to_string e) ] | ||
| Found lib -> variant "Found" [ Lib_info.to_dyn Path.to_dyn lib ] | ||
| Found libs -> variant "Found" [ (Dyn.list (Lib_info.to_dyn Path.to_dyn)) libs ] | ||
| Hidden h -> variant "Hidden" [ Hidden.to_dyn (Lib_info.to_dyn Path.to_dyn) h ] | ||
| Ignore -> variant "Ignore" [] | ||
| Redirect (_, (_, name)) -> variant "Redirect" [ Lib_name.to_dyn name ] | ||
| Redirect_in_the_same_db (_, name) -> | ||
variant "Redirect_in_the_same_db" [ Lib_name.to_dyn name ] | ||
| Redirect_in_the_same_db redirects -> | ||
variant | ||
"Redirect_in_the_same_db" | ||
[ (Dyn.list (fun (_, name) -> Lib_name.to_dyn name)) redirects ] | ||
| Deprecated_library_name (_, name) -> | ||
variant "Deprecated_library_name" [ Lib_name.to_dyn name ] | ||
;; | ||
end | ||
|
||
|
@@ -1827,9 +1902,9 @@ module DB = struct | |
let open Memo.O in | ||
Findlib.find findlib name | ||
>>| function | ||
| Ok (Library pkg) -> Found (Dune_package.Lib.info pkg) | ||
| Ok (Library pkg) -> Found [ Dune_package.Lib.info pkg ] | ||
| Ok (Deprecated_library_name d) -> | ||
Redirect_in_the_same_db (d.loc, d.new_public_name) | ||
Deprecated_library_name (d.loc, d.new_public_name) | ||
| Ok (Hidden_library pkg) -> Hidden (Hidden.unsatisfied_exist_if pkg) | ||
| Error e -> | ||
(match e with | ||
|
@@ -1866,6 +1941,14 @@ module DB = struct | |
| Ignore | Not_found | Invalid _ | Hidden _ -> None | ||
;; | ||
|
||
let find_invalid t name = | ||
let open Memo.O in | ||
Resolve_names.find_internal t name | ||
>>| function | ||
| Invalid err -> Some err | ||
| Found _ | Ignore | Not_found | Hidden _ -> None | ||
;; | ||
|
||
let find_even_when_hidden t name = | ||
let open Memo.O in | ||
Resolve_names.find_internal t name | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understood that "available" means rather "exists". For inexistent libraries,
enabled_in_context
might returntrue
surprisingly, so we have to keep both conditions in the check.