Skip to content

Commit c5d5ec8

Browse files
committed
Introduce an efficient typing rule for let-bindings in Typeops.
When the expand_let typing flag is set in the environment, we change the kernel typing rule for let-bindings from let x := t in u : T{x := t} to let x := t in u : let x := t in T. We cannot do this by default since it may change the inferred type for some expressions, which is returned when the expected type is not provided. To work around this, we statically set the flag in expressions for which the precise inferred type is not relevant. For now there is no user-facing flag that would allow setting this option in a more fine-grained way though, but it is easy to fix. This is a revival of #13606 and a partial fix of #11838. The latter still suffers from superlinear blowups in unrelated parts of the kernel, namely VM and native compilation.
1 parent 4db61d1 commit c5d5ec8

File tree

7 files changed

+32
-9
lines changed

7 files changed

+32
-9
lines changed

checker/checkFlags.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ let set_local_flags flags env =
2323
share_reduction = flags.share_reduction;
2424
unfold_dep_heuristic = flags.unfold_dep_heuristic;
2525
allow_uip = flags.allow_uip;
26+
expand_let = flags.expand_let;
2627
(* These flags may not *)
2728
enable_VM = envflags.enable_VM;
2829
enable_native_compiler = envflags.enable_native_compiler;

checker/values.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ let v_typing_flags =
357357
v_tuple "typing_flags"
358358
[|v_bool; v_bool; v_bool; v_bool;
359359
v_oracle; v_bool; v_bool;
360-
v_bool; v_bool; v_bool; v_bool; v_bool; v_bool|]
360+
v_bool; v_bool; v_bool; v_bool; v_bool; v_bool; v_bool|]
361361

362362
let v_univs = v_sum "universes" 1 [|[|v_abs_context|]|]
363363

kernel/constant_typing.ml

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ open UVars
2424

2525
module NamedDecl = Context.Named.Declaration
2626

27+
(** Use this function when typing terms where the precise value of the inferred
28+
type from the equivalence class of conversion does not matter. It makes it
29+
more efficient. *)
30+
let unset_let_expansion env =
31+
Environ.set_typing_flags { (Environ.typing_flags env) with expand_let = false } env
32+
2733
(* Checks the section variables for the body.
2834
Returns the closure of the union with the variables in the type.
2935
*)
@@ -174,7 +180,8 @@ let infer_primitive env { prim_entry_type = utyp; prim_entry_content = p; } =
174180
let infer_symbol env { symb_entry_universes; symb_entry_unfold_fix; symb_entry_type } =
175181
let env, usubst, _, univs = process_universes env symb_entry_universes in
176182
let symb_entry_type = Vars.subst_univs_level_constr usubst symb_entry_type in
177-
let j = Typeops.infer env symb_entry_type in
183+
(* Inferred type is not returned *)
184+
let j = Typeops.infer (unset_let_expansion env) symb_entry_type in
178185
let r = Typeops.assumption_of_judgment env j in
179186
{
180187
const_hyps = [];
@@ -196,7 +203,8 @@ let make_univ_hyps = function
196203
let infer_parameter ~sec_univs env entry =
197204
let env, usubst, _, univs = process_universes env entry.parameter_entry_universes in
198205
let typ = Vars.subst_univs_level_constr usubst entry.parameter_entry_type in
199-
let j = Typeops.infer env typ in
206+
(* Inferred type is not returned *)
207+
let j = Typeops.infer (unset_let_expansion env) typ in
200208
let r = Typeops.assumption_of_judgment env j in
201209
let typ = j.uj_val in
202210
let undef = Undef entry.parameter_entry_inline_code in
@@ -217,7 +225,9 @@ let infer_definition ~sec_univs env entry =
217225
let env, usubst, _, univs = process_universes env entry.definition_entry_universes in
218226
let body = Vars.subst_univs_level_constr usubst entry.definition_entry_body in
219227
let hbody = HConstr.of_constr env body in
220-
let j = Typeops.infer_hconstr env hbody in
228+
(* When the expected type is provided, don't care about the inferred type *)
229+
let jenv = if Option.is_empty entry.definition_entry_type then env else unset_let_expansion env in
230+
let j = Typeops.infer_hconstr jenv hbody in
221231
let typ = match entry.definition_entry_type with
222232
| None ->
223233
j.uj_type
@@ -284,7 +294,8 @@ let check_delayed (type a) (handle : a effect_handler) tyenv (body : a proof_out
284294
(* Note: non-trivial trusted side-effects only in monomorphic case *)
285295
let () =
286296
let eff_body, eff_env = skip_trusted_seff valid_signatures hbody env in
287-
let j = Typeops.infer_hconstr eff_env eff_body in
297+
(* Inferred type is not returned *)
298+
let j = Typeops.infer_hconstr (unset_let_expansion eff_env) eff_body in
288299
let () = assert (HConstr.self eff_body == j.uj_val) in
289300
let j = { uj_val = HConstr.self hbody; uj_type = j.uj_type } in
290301
Typeops.check_cast eff_env j DEFAULTcast tyj
@@ -302,12 +313,15 @@ let check_delayed (type a) (handle : a effect_handler) tyenv (body : a proof_out
302313
(*s Global and local constant declaration. *)
303314

304315
let infer_local_assum env t =
305-
let j = Typeops.infer env t in
316+
(* Inferred type is not returned *)
317+
let j = Typeops.infer (unset_let_expansion env) t in
306318
let t = Typeops.assumption_of_judgment env j in
307319
j.uj_val, t
308320

309321
let infer_local_def env _id { secdef_body; secdef_type; } =
310-
let j = Typeops.infer env secdef_body in
322+
(* When the expected type is provided, don't care about the inferred type *)
323+
let jenv = if Option.is_empty secdef_type then env else unset_let_expansion env in
324+
let j = Typeops.infer jenv secdef_body in
311325
let typ = match secdef_type with
312326
| None -> j.uj_type
313327
| Some typ ->

kernel/declarations.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ type typing_flags = {
8989
unfold_dep_heuristic : bool;
9090
(** If [true], use dependency heuristic when unfolding constants during conversion *)
9191

92+
expand_let : bool;
93+
(** Whether to infer [let x := t in u : T{x := t}] or [let x := t in u : let x := t in T] *)
94+
9295
enable_VM : bool;
9396
(** If [false], all VM conversions fall back to interpreted ones *)
9497

kernel/declareops.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ let safe_flags oracle = {
2727
conv_oracle = oracle;
2828
share_reduction = true;
2929
unfold_dep_heuristic = false;
30+
expand_let = true;
3031
enable_VM = true;
3132
enable_native_compiler = true;
3233
indices_matter = true;

kernel/environ.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ let same_flags {
577577
indices_matter;
578578
share_reduction;
579579
unfold_dep_heuristic;
580+
expand_let;
580581
enable_VM;
581582
enable_native_compiler;
582583
impredicative_set;
@@ -591,6 +592,7 @@ let same_flags {
591592
indices_matter == alt.indices_matter &&
592593
share_reduction == alt.share_reduction &&
593594
unfold_dep_heuristic == alt.unfold_dep_heuristic &&
595+
expand_let == alt.expand_let &&
594596
enable_VM == alt.enable_VM &&
595597
enable_native_compiler == alt.enable_native_compiler &&
596598
impredicative_set == alt.impredicative_set &&

kernel/typeops.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ and execute_aux tbl env cstr =
733733
let () = check_cast env c1 c1t DEFAULTcast c2 in
734734
let env1 = push_rel (LocalDef (name,c1,c2)) env in
735735
let c3t = execute tbl env1 c3 in
736-
subst1 c1 c3t
736+
if (Environ.typing_flags env).expand_let then subst1 c1 c3t else mkLetIn (name, c1, c2, c3t)
737737

738738
| Cast (c,k,t) ->
739739
let ct = execute tbl env c in
@@ -919,7 +919,9 @@ let infer_type env constr =
919919
let () = check_wellformed_universes env constr in
920920
let hconstr = HConstr.of_constr env constr in
921921
let constr = HConstr.self hconstr in
922-
let t = execute env hconstr in
922+
(* Returned j_type is not observable *)
923+
let tenv = Environ.set_typing_flags { (Environ.typing_flags env) with expand_let = false } env in
924+
let t = execute tenv hconstr in
923925
let s = check_type env constr t in
924926
{utj_val = constr; utj_type = s}
925927

0 commit comments

Comments
 (0)