@@ -54,40 +54,46 @@ let invalid_variable_error ~loc variable =
5454 [ Pp. textf " Variable %S is not supported." (OpamVariable. to_string variable) ]
5555;;
5656
57- let opam_variable_to_slang ~loc packages variable =
58- let variable_string = OpamVariable. to_string variable in
59- let convert_with_package_name package_name =
60- match is_valid_package_variable_name variable_string with
61- | false -> invalid_variable_error ~loc variable
62- | true ->
63- let pform =
64- let name = Package_variable_name. of_string variable_string in
65- let scope : Package_variable.Scope.t =
66- match package_name with
67- | None -> Self
68- | Some p -> Package (Package_name. of_opam_package_name p)
69- in
70- Package_variable. to_pform { Package_variable. name; scope }
71- in
72- Slang. pform pform
57+ let opam_variable_to_slang =
58+ let opam_var_to_pform variable_name scope =
59+ Package_variable. to_pform { Package_variable. name = variable_name; scope }
60+ |> Slang. pform
7361 in
74- match packages with
75- | [] ->
76- (match is_valid_global_variable_name variable_string with
77- | false ->
78- (* Note that there's no syntactic distinction between global variables
62+ fun ~loc ~packages_in_solution packages variable ->
63+ let variable_string = OpamVariable. to_string variable in
64+ let variable_name = Package_variable_name. of_string variable_string in
65+ let convert_with_package_name package_name =
66+ match is_valid_package_variable_name variable_string with
67+ | false -> invalid_variable_error ~loc variable
68+ | true ->
69+ (match package_name with
70+ | Some p ->
71+ let pkg_name = Package_name. of_opam_package_name p in
72+ let pform = opam_var_to_pform variable_name (Package pkg_name) in
73+ if Package_name.Map. mem packages_in_solution pkg_name
74+ then pform
75+ else
76+ Package_variable_name. absent_package_value variable_name
77+ |> Option. value ~default: pform
78+ | None -> opam_var_to_pform variable_name Self )
79+ in
80+ match packages with
81+ | [] ->
82+ (match is_valid_global_variable_name variable_string with
83+ | false ->
84+ (* Note that there's no syntactic distinction between global variables
7985 and package variables in the current package. This check will prevent
8086 invalid global variable names from being used for package variables in the
8187 current package where the optional qualifier "_:" is omitted. *)
82- invalid_variable_error ~loc variable
83- | true ->
84- (match Pform.Var. of_opam_global_variable_name variable_string with
85- | Some global_var -> Slang. pform (Pform. Var global_var)
86- | None -> convert_with_package_name None ))
87- | [ package_name ] -> convert_with_package_name package_name
88- | many ->
89- let many = List. map many ~f: convert_with_package_name in
90- Slang. blang (Blang. And (List. map many ~f: (fun slang -> Blang. Expr slang)))
88+ invalid_variable_error ~loc variable
89+ | true ->
90+ (match Pform.Var. of_opam_global_variable_name variable_string with
91+ | Some global_var -> Slang. pform (Pform. Var global_var)
92+ | None -> convert_with_package_name None ))
93+ | [ package_name ] -> convert_with_package_name package_name
94+ | many ->
95+ let many = List. map many ~f: convert_with_package_name in
96+ Slang. blang (Blang. And (List. map many ~f: (fun slang -> Blang. Expr slang)))
9197;;
9298
9399(* Handles the special case for packages whose names contain '+' characters
@@ -113,29 +119,38 @@ let desugar_special_string_interpolation_syntax
113119 | _ -> fident
114120;;
115121
116- let opam_fident_to_slang ~loc fident =
122+ let opam_fident_to_slang ~loc ~ packages_in_solution fident =
117123 let packages, variable, string_converter =
118124 OpamFilter. desugar_fident fident |> desugar_special_string_interpolation_syntax
119125 in
120- let slang = opam_variable_to_slang ~loc packages variable in
126+ let slang = opam_variable_to_slang ~loc ~packages_in_solution packages variable in
121127 match string_converter with
122128 | None -> slang
123129 | Some (then_ , else_ ) ->
124130 (* The "else" case is also used when evaluating the condition would expand
125131 an undefined variable. The catch_undefined_var operator is used to
126132 convert expressions that throw undefined variable exceptions into false.
127133 *)
128- let condition =
129- Blang. Expr (Slang. catch_undefined_var slang ~fallback: (Slang. bool false ))
134+ let is_known_false =
135+ match slang with
136+ | Form (_ , Blang (Blang. Const false )) -> true
137+ | _ -> false
130138 in
131- Slang. if_ condition ~then_: (Slang. text then_) ~else_: (Slang. text else_)
139+ if is_known_false
140+ then Slang. text else_
141+ else (
142+ let condition =
143+ Blang. Expr (Slang. catch_undefined_var slang ~fallback: (Slang. bool false ))
144+ in
145+ Slang. if_ condition ~then_: (Slang. text then_) ~else_: (Slang. text else_))
132146;;
133147
134- let opam_raw_fident_to_slang ~loc raw_ident =
135- OpamTypesBase. filter_ident_of_string raw_ident |> opam_fident_to_slang ~loc
148+ let opam_raw_fident_to_slang ~loc ~packages_in_solution raw_ident =
149+ OpamTypesBase. filter_ident_of_string raw_ident
150+ |> opam_fident_to_slang ~loc ~packages_in_solution
136151;;
137152
138- let opam_string_to_slang ~package ~loc opam_string =
153+ let opam_string_to_slang ~packages_in_solution ~ package ~loc opam_string =
139154 Re.Seq. split_full OpamFilter. string_interp_regex opam_string
140155 |> Seq. map ~f: (function
141156 | `Text text -> Slang. text text
@@ -146,7 +161,7 @@ let opam_string_to_slang ~package ~loc opam_string =
146161 when String. starts_with ~prefix: " %{" interp
147162 && String. ends_with ~suffix: " }%" interp ->
148163 let ident = String. sub ~pos: 2 ~len: (String. length interp - 4 ) interp in
149- opam_raw_fident_to_slang ~loc ident
164+ opam_raw_fident_to_slang ~loc ~packages_in_solution ident
150165 | other ->
151166 User_error. raise
152167 ~loc
@@ -216,11 +231,13 @@ let resolve_depopts ~resolve depopts =
216231 These two Slang operators are used to emulate Opam's undefined value
217232 semantics.
218233*)
219- let filter_to_blang ~package ~loc filter =
234+ let filter_to_blang ~packages_in_solution ~ package ~loc filter =
220235 let filter_to_slang (filter : OpamTypes.filter ) =
221236 match filter with
222- | FString s -> opam_string_to_slang ~package ~loc s
223- | FIdent fident -> opam_fident_to_slang ~loc fident
237+ | FString s -> opam_string_to_slang ~packages_in_solution ~package ~loc s
238+ | FIdent fident ->
239+ (* FIdent in filter context is truthy, so don't substitute absent values *)
240+ opam_fident_to_slang ~loc ~packages_in_solution fident
224241 | other ->
225242 Code_error. raise
226243 " The opam file parser should only allow identifiers and strings in places where \
@@ -268,6 +285,7 @@ let filter_to_blang ~package ~loc filter =
268285;;
269286
270287let opam_commands_to_actions
288+ ~packages_in_solution
271289 get_solver_var
272290 loc
273291 package
@@ -287,8 +305,9 @@ let opam_commands_to_actions
287305 let slang =
288306 let slang =
289307 match simple_arg with
290- | CString s -> opam_string_to_slang ~package ~loc s
291- | CIdent ident -> opam_raw_fident_to_slang ~loc ident
308+ | CString s -> opam_string_to_slang ~packages_in_solution ~package ~loc s
309+ | CIdent ident ->
310+ opam_raw_fident_to_slang ~loc ~packages_in_solution ident
292311 in
293312 Slang. simplify slang
294313 in
@@ -298,8 +317,9 @@ let opam_commands_to_actions
298317 | None -> slang
299318 | Some filter ->
300319 let filter_blang =
301- filter_to_blang ~package ~loc filter |> Slang. simplify_blang
302- and slang = slang in
320+ filter_to_blang ~packages_in_solution ~package ~loc filter
321+ |> Slang. simplify_blang
322+ in
303323 let filter_blang_handling_undefined =
304324 (* Wrap the blang filter so that if any undefined
305325 variables are expanded while evaluating the filter,
@@ -318,17 +338,18 @@ let opam_commands_to_actions
318338 if List. is_empty terms
319339 then None
320340 else (
321- let action =
322- let action = Action. Run terms in
323- match filter with
324- | None -> action
325- | Some filter ->
326- let condition =
327- filter_to_blang ~package ~loc filter |> Slang. simplify_blang
328- in
329- Action. When (condition, action)
330- in
331- Some action))
341+ let action = Action. Run terms in
342+ match filter with
343+ | None -> Some action
344+ | Some filter ->
345+ let condition =
346+ filter_to_blang ~packages_in_solution ~package ~loc filter
347+ |> Slang. simplify_blang
348+ in
349+ (match condition with
350+ | Const true -> Some action
351+ | Const false -> None
352+ | _ -> Some (Action. When (condition, action)))))
332353;;
333354
334355(* Standard package variables that are always defined at build time.
@@ -379,12 +400,13 @@ let rec filter_vars_are_defined : OpamTypes.filter -> bool = function
379400
380401 Depexts with filters that reference undefined variables are excluded, as
381402 they would error at build time. *)
382- let depexts_to_conditional_external_dependencies package depexts =
403+ let depexts_to_conditional_external_dependencies ~ packages_in_solution package depexts =
383404 List. filter_map depexts ~f: (fun (sys_pkgs , filter ) ->
384405 let open Option.O in
385406 let * () = Option. some_if (filter_vars_are_defined filter) () in
386407 let condition =
387- filter_to_blang ~package ~loc: Loc. none filter |> Slang. simplify_blang
408+ filter_to_blang ~packages_in_solution ~package ~loc: Loc. none filter
409+ |> Slang. simplify_blang
388410 in
389411 let + () = Option. some_if (not (Slang.Blang. equal condition Slang.Blang. false_)) () in
390412 let external_package_names =
@@ -489,6 +511,7 @@ let opam_package_to_lock_file_pkg
489511 Solver_stats.Updater. expand_variable stats_updater variable_name;
490512 Solver_env. get solver_env variable_name
491513 in
514+ let packages_in_solution = version_by_package_name in
492515 let build_command =
493516 if Resolved_package. dune_build resolved_package
494517 then Some Lock_dir.Build_command. Dune
@@ -512,12 +535,17 @@ let opam_package_to_lock_file_pkg
512535 | None -> action
513536 | Some filter ->
514537 let blang =
515- filter_to_blang ~package: opam_package ~loc: Loc. none filter
538+ filter_to_blang
539+ ~packages_in_solution
540+ ~package: opam_package
541+ ~loc: Loc. none
542+ filter
516543 |> Slang. simplify_blang
517544 in
518545 Action. When (blang, action))
519546 and build_step =
520547 opam_commands_to_actions
548+ ~packages_in_solution
521549 get_solver_var
522550 loc
523551 opam_package
@@ -548,6 +576,7 @@ let opam_package_to_lock_file_pkg
548576 if portable_lock_dir
549577 then
550578 depexts_to_conditional_external_dependencies
579+ ~packages_in_solution
551580 opam_package
552581 (OpamFile.OPAM. depexts opam_file)
553582 else (
@@ -566,7 +595,7 @@ let opam_package_to_lock_file_pkg
566595 in
567596 let install_command =
568597 OpamFile.OPAM. install opam_file
569- |> opam_commands_to_actions get_solver_var loc opam_package
598+ |> opam_commands_to_actions ~packages_in_solution get_solver_var loc opam_package
570599 |> make_action
571600 |> Option. map ~f: (fun action -> lockfile_field_choice (build_env action))
572601 |> Option. value ~default: Lock_dir.Conditional_choice. empty
0 commit comments