package vscoq-language-server
VSCoq language server
Install
Dune Dependency
Authors
Maintainers
Sources
vscoq-language-server-2.2.3.tar.gz
md5=c8f21aebcdbc9a82201e0ae2ef27e381
sha512=aa520998f9d4a1f80327a584ddb9a3ad8cea3a846b45784231a4a29a1734d8deed0670ba66fabd097016641c619fd580e09f1da060bfdce4bf4275396d21a8b6
doc/src/vscoq-language-server.dm/completionSuggester.ml.html
Source file completionSuggester.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
(**************************************************************************) (* *) (* VSCoq *) (* *) (* Copyright INRIA and contributors *) (* (see version control and README file for authors & dates) *) (* *) (**************************************************************************) (* *) (* This file is distributed under the terms of the MIT License. *) (* See LICENSE file. *) (* *) (**************************************************************************) open Protocol module CompactedDecl = Context.Compacted.Declaration open Printer open EConstr open Names open Types let Log log = Log.mk_log "completionSuggester" module TypeCompare = struct type t = types let compare = compare end let takeSkip n l = let rec sub_list n accu l = match l with | [] -> accu, [] | hd :: tl -> if n = 0 then accu, tl else sub_list (n - 1) (hd :: accu) tl in let take, skip = sub_list n [] l in List.rev (take), skip module Atomics = Set.Make(TypeCompare) module HypothesisMap = Map.Make (struct type t = Id.t let compare = compare end) let mk_hyp d (env,l) = let d' = CompactedDecl.to_named_context d in let env' = List.fold_right EConstr.push_named d' env in let ids, typ = match d with | CompactedDecl.LocalAssum (ids, typ) -> ids, typ | CompactedDecl.LocalDef (ids,_,typ) -> ids, typ in let ids' = List.map (fun id -> id.Context.binder_name) ids in let m = List.fold_right (fun id acc -> HypothesisMap.add id typ acc) ids' l in (env', m) let get_hyps env sigma goal = let EvarInfo evi = Evd.find sigma goal in let env = Evd.evar_filtered_env env evi in let min_env = Environ.reset_context env in let (_env, hyps) = Context.Compacted.fold (mk_hyp) (Termops.compact_named_context sigma (EConstr.named_context env)) ~init:(min_env, HypothesisMap.empty) in hyps let type_kind_opt sigma t = try Some (kind_of_type sigma t) with _ -> None [%%if coq = "8.18" || coq = "8.19"] let type_size sigma t : int = let rec aux u = match kind sigma u with | Sort _ -> 1 | Cast (c,_,t) -> aux c + aux t | Prod (_,t,c) -> aux t + aux c | LetIn (_,b,t,c) -> aux b + aux t + aux c | App (c,l) -> Array.map aux l |> Array.fold_left (+) (aux c) | Rel _ -> 1 | (Meta _ | Var _ | Evar _ | Const _ | Proj _ | Case _ | Fix _ | CoFix _ | Ind _) -> 1 | (Lambda _ | Construct _ | Array _ | Int _ | Float _) -> 1 in aux t [%%else] let type_size sigma t : int = let rec aux u = match kind sigma u with | Sort _ -> 1 | Cast (c,_,t) -> aux c + aux t | Prod (_,t,c) -> aux t + aux c | LetIn (_,b,t,c) -> aux b + aux t + aux c | App (c,l) -> Array.map aux l |> Array.fold_left (+) (aux c) | Rel _ -> 1 | (Meta _ | Var _ | Evar _ | Const _ | Proj _ | Case _ | Fix _ | CoFix _ | Ind _) -> 1 | (Lambda _ | Construct _ | Array _ | Int _ | Float _ | String _) -> 1 in aux t [%%endif] module TypeIntersection = struct let atomic_types sigma t: Atomics.t = let rec aux t : types list = match (type_kind_opt sigma t) with | Some SortType _ -> [] (* Might be possible to get atomics from also *) | Some CastType (tt, t) -> aux tt @ aux t | Some ProdType (_, t1, t2) -> aux t1 @ aux t2 | Some LetInType _ -> [] | Some AtomicType (t, ta) -> t :: (Array.map aux ta |> Array.to_list |> List.flatten); | None -> [] (* Lol :) *) in aux t |> Atomics.of_list let compare_atomics (goal : Atomics.t) (a1, _ : Atomics.t * _) (a2, _ : Atomics.t * _) : int = match (Atomics.inter a1 goal, Atomics.inter a2 goal) with | r1, r2 when Atomics.cardinal r1 = Atomics.cardinal r2 -> (* If the size is equal, priotize the one with fewest types *) compare (Atomics.cardinal a1) (Atomics.cardinal a2) | r1, r2 -> (* Return the set with largest overlap, so we sort in increasing order swap the arguments *) compare (Atomics.cardinal r2) (Atomics.cardinal r1) let split_types sigma c = let (list, other_c) = decompose_prod sigma c in list |> List.map snd |> List.cons other_c |> List.map (fun typ -> atomic_types sigma typ) |> List.fold_left (fun (acc, result) item -> (Atomics.union acc item, Atomics.union acc item :: result)) (Atomics.empty, []) |> snd let best_subtype sigma goal c = c |> split_types sigma |> List.map (fun a -> (a, a)) |> List.stable_sort (compare_atomics goal) |> List.hd |> fst let rank (goal : Evd.econstr) sigma _ (lemmas : CompletionItems.completion_item list) : CompletionItems.completion_item list = (*Split type intersection: Split the lemmas by implications, compare the suffix to the goal, pick best match*) let goal = atomic_types sigma goal in let lemmaTypes = List.map (fun (l : CompletionItems.completion_item) -> let best = best_subtype sigma goal (of_constr l.typ) in (best, l) ) lemmas in List.stable_sort (compare_atomics goal) lemmaTypes |> List.map snd end type bruijn_level = int module Structured = struct type unifier = | SortUniType of ESorts.t * bruijn_level | AtomicUniType of types * unifier array (* map from bruijn_level to unifier *) module UM = Map.Make(struct type t = bruijn_level let compare = compare end) (* This is extremely slow, we should not convert it to a list. *) let filter_options a = a |> Array.to_list |> Option.List.flatten |> Array.of_list let unifier_kind sigma (hyps : types HypothesisMap.t) (t : types) : unifier option = let rec aux bruijn t = match kind sigma t with | Sort s -> SortUniType (s, List.length bruijn) |> Option.make | Cast (c,_,_) -> aux bruijn c | Prod (_,t,c) -> aux (aux bruijn t :: bruijn) c (* Possibly the index should be assigned here instead and be a thing for both types. *) | LetIn (_,_,t,c) -> aux (aux bruijn t :: bruijn) c | App (c,l) -> let l' = Array.map (aux bruijn) l in AtomicUniType (c, filter_options l') |> Option.make | Rel i -> List.nth bruijn (i-1) | Var v when HypothesisMap.mem v hyps -> aux bruijn (HypothesisMap.find v hyps) | (Meta _ | Var _ | Evar _ | Const _ | Proj _ | Case _ | Fix _ | CoFix _ | Ind _) -> AtomicUniType (t,[||]) |> Option.make | (Lambda _ | Construct _ | _ ) -> None in aux [] t let rec matches evd (u1: unifier) (u2: unifier) = match (u1, u2) with | SortUniType (s1, _), SortUniType (s2, _) -> ESorts.equal evd s1 s2 | SortUniType _, _ -> false | _, SortUniType _ -> false (* TODO: Maybe add to UM? Maybe not? The UM is not the goal. *) | AtomicUniType (t1, ua1), AtomicUniType (t2, ua2) -> let c = EConstr.compare_constr evd (EConstr.eq_constr evd) t1 t2 in if c then let rec aux ua1 ua2 = match (ua1, ua2) with | [], [] -> true | [], _ | _, [] -> false | u1 :: ua1, u2 :: ua2 -> let c = matches evd u1 u2 in if c then aux ua1 ua2 else false in aux (Array.to_list ua1) (Array.to_list ua2) else false let score_unifier atomic_factor evd (goal : unifier) (u : unifier) : float = let rec aux (um : unifier UM.t) g u : (float * unifier UM.t) = match (g, u) with | SortUniType (s1, _), SortUniType (s2, _) -> if ESorts.equal evd s1 s2 then (1., um) else (0., um) (* We might want to check if the t in AtomicUniType actually belongs in the sort*) | SortUniType _, _ -> (0., um) (* If the goal has a sort then it has to match *) | AtomicUniType (_, _), SortUniType (s, i) -> if UM.mem i um then let u = UM.find i um in matches evd u (SortUniType (s, i)) |> Bool.to_float |> fun x -> (x, um) else (1., UM.add i u um) | AtomicUniType (t1, ua1), AtomicUniType (t2, ua2) -> let c = EConstr.compare_constr evd (EConstr.eq_constr evd) t1 t2 |> Bool.to_float |> (Float.mul atomic_factor) in let c = if isVar evd t1 && isVar evd t2 then Float.mul c 2.0 else c in if Array.length ua1 <> Array.length ua2 then (c, um) else let (score, um) = Array.fold_left (fun (acc, um) (u1, u2) -> let (s, um) = aux um u1 u2 in (Float.add acc s, um) ) (c, um) (Array.combine ua1 ua2) in (score, um) in aux UM.empty goal u |> fst let unpack_unifier u : unifier list = let res = ref [] in let rec aux u = match u with | SortUniType (_, _) -> (); | AtomicUniType (_, ua) -> res := u :: !res; Array.iter aux ua in aux u; !res let rec size_unifier u = match u with | SortUniType (_, _) -> 1l | AtomicUniType (_, ua) -> Array.fold_left (fun acc u -> Int32.add acc (size_unifier u)) 1l ua (* A Lower score is better as we are sorting in ascending order *) let rank (options: Settings.Completion.t) (goal, goal_evar) sigma env lemmas : CompletionItems.completion_item list = let size_impact = options.sizeFactor in let atomic_factor = options.atomicFactor in let finalScore score size = Float.sub size (Float.mul score size_impact) in let hyps = get_hyps env sigma goal_evar in match (unifier_kind sigma hyps goal, unifier_kind sigma HypothesisMap.empty goal) with | None, _ | _, None -> lemmas | Some goalUnf, Some goalUnfNoHypothesisSub -> let lemmaUnfs = List.map (fun (l : CompletionItems.completion_item) -> match (unifier_kind sigma HypothesisMap.empty (of_constr l.typ)) with | None -> ((Float.min_float), l) | Some unf -> let scores = List.map (score_unifier atomic_factor sigma goalUnf) (unpack_unifier unf) in let scores = scores @ (List.map (score_unifier atomic_factor sigma goalUnfNoHypothesisSub) (unpack_unifier unf)) in let size = size_unifier unf |> Int32.to_float in let maxScore = List.fold_left Float.max 0. scores in let final = finalScore maxScore size in l.debug_info <- (Printf.sprintf "Score: %f, Size: %f, Final Score: %f" maxScore size final); (final, l) ) lemmas in let sorted = List.stable_sort (fun (x, _) (y, _) -> Float.compare x y) lemmaUnfs in List.map snd sorted end module SelectiveUnification = struct let rankByUnifiability (goal : Evd.econstr) sigma env (lemmas : CompletionItems.completion_item list) : CompletionItems.completion_item list = let goal_size = type_size sigma goal in let worst_value = 1000 in (* the worst value we expect to assign. This value is mostly arbitrary*) let make_sortable (lemma : CompletionItems.completion_item) = let flags = Evarconv.default_flags_of TransparentState.full in let rec aux (iterations: int) (typ : types) : (CompletionItems.completion_item * int)= if type_size sigma typ + goal_size > 500 then (lemma, worst_value) (*The number 500 is an arbitrary limit on how big lemmas we are willing to look at*) else let res = Evarconv.evar_conv_x flags env sigma Conversion.CONV goal typ in match res with | Success _ -> ({lemma with completes = if iterations = 0 then Some Fully else Some Partially}, iterations) | UnifFailure (_, _) -> match kind sigma typ with | Prod (_,_,c) -> aux (iterations + 1) c | Cast (c,_,_) -> aux iterations c | _ -> ({lemma with completes = Some No_completion}, worst_value) in try aux 0 (of_constr lemma.typ) with e -> Printf.sprintf "Error in Split Unification: %s for %s\n%!" (Printexc.to_string e) (Pp.string_of_ppcmds (pr_global lemma.ref)) |> log; ({lemma with completes = Some No_completion}, worst_value) in lemmas |> List.map make_sortable |> List.stable_sort (fun a b -> compare (snd a) (snd b)) |> List.map fst let selectiveRank (options: Settings.Completion.t) (goal : Evd.econstr) sigma env (lemmas : CompletionItems.completion_item list) : CompletionItems.completion_item list = try let take, skip = takeSkip options.unificationLimit lemmas in List.append (rankByUnifiability goal sigma env take) skip with e -> log ("Error in Split Unification: %s" ^ (Printexc.to_string e)); lemmas let rank = selectiveRank end let rank_choices (options: Settings.Completion.t) (goal, goal_evar) sigma env lemmas = let open Settings.Completion.RankingAlgoritm in match options.algorithm with | SplitTypeIntersection -> TypeIntersection.rank goal sigma env lemmas | StructuredSplitUnification -> SelectiveUnification.rank options goal sigma env (Structured.rank options (goal, goal_evar) sigma env lemmas) let get_goal_type_opt env Proof.{ goals; sigma; _ } = List.nth_opt goals 0 |> Option.map (fun goal -> let evi = Evd.find_undefined sigma goal in let env = Evd.evar_filtered_env env evi in Evd.evar_concl evi, sigma, env, goal ) let get_completion_items env proof lemmas options = try match get_goal_type_opt env proof with | None -> lemmas | Some (goal, sigma, env, goal_evar) -> rank_choices options (goal, goal_evar) sigma env lemmas with e -> log ("Ranking of lemmas failed: " ^ (Printexc.to_string e)); lemmas [%%if coq = "8.18"] let generic_search e s f = Search.generic_search e (fun r k e c -> f r k e s c) [%%else] let generic_search = Search.generic_search [%%endif] let get_lemmas sigma env = let open CompletionItems in let results = ref [] in let display ref _kind env sigma c = results := mk_completion_item sigma ref env c :: results.contents; in generic_search env sigma display; results.contents let get_completions options st = Vernacstate.unfreeze_full_state st; match st.interp.lemmas with | None -> None | Some lemmas -> let proof = Proof.data (lemmas |> Vernacstate.LemmaStack.with_top ~f:Declare.Proof.get) in let env = Global.env () in let sigma = proof.sigma in let lemmas = get_lemmas sigma env in Some (get_completion_items env proof lemmas options)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>