Skip to content

Commit 922cb1f

Browse files
committed
perf merge
3 parents 2aad2f8 + 2fd0af9 + 136a703 commit 922cb1f

4 files changed

Lines changed: 333 additions & 37 deletions

File tree

src/Lean/Meta/Basic.lean

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,19 @@ structure SynthInstanceCacheKey where
337337
-/
338338
normFVarTypes : Array Expr := #[]
339339
/--
340-
Value of `synthPendingDepth` when instance was synthesized or failed to be synthesized.
341-
See issue #2522.
340+
Value of `synthPendingDepth` when the instance was synthesized or failed to be
341+
synthesized, or `none` if the result can be reused at other depths.
342+
343+
`synthPendingDepth` can influence the result of a query because `synthPending` gives up
344+
when `synthPendingDepth > maxSynthPendingDepth`, so a result may not be reused at a
345+
different depth (see issue #2522). However, this is the *only* way the depth can influence
346+
a query. Thus, if no `synthPending` invocation gave up while synthesizing an instance, the
347+
result is valid at every depth at which the guard still cannot trigger, and is stored with
348+
`synthPendingDepth := none` together with a validity bound in the cache entry (see
349+
`SynthInstanceCacheEntry.relSynthPendingDepth`). Only results whose synthesis hit the
350+
give-up threshold remain keyed by their exact depth.
342351
-/
343-
synthPendingDepth : Nat
352+
synthPendingDepth : Option Nat
344353
/--
345354
Namespaces with scoped instances that are currently activated (e.g. via `open`), in canonical
346355
order. Keying the cache by this set keeps entries from outside a scope valid after the scope
@@ -379,7 +388,20 @@ structure AbstractMVarsResult where
379388
def AbstractMVarsResult.numMVars (r : AbstractMVarsResult) : Nat :=
380389
r.mvars.size
381390

382-
abbrev SynthInstanceCache := PersistentHashMap SynthInstanceCacheKey (Option AbstractMVarsResult)
391+
/-- Entry of the type class resolution cache. -/
392+
structure SynthInstanceCacheEntry where
393+
/--
394+
Maximum `synthPendingDepth` at which a `synthPending` decision was reached during the
395+
synthesis, relative to the query's own `synthPendingDepth`, or `none` if no such decision
396+
was reached. An entry stored under `synthPendingDepth := none` may be reused by a query at
397+
depth `d` iff `relSynthPendingDepth` is `none` or `d + relSynthPendingDepth` does not
398+
exceed `maxSynthPendingDepth`: under that bound no `synthPending` invocation can reach the
399+
give-up threshold, so the synthesis behaves identically at depth `d`.
400+
-/
401+
relSynthPendingDepth : Option Nat := none
402+
result : Option AbstractMVarsResult
403+
404+
abbrev SynthInstanceCache := PersistentHashMap SynthInstanceCacheKey SynthInstanceCacheEntry
383405

384406
-- Key for `InferType` and `WHNF` caches
385407
structure ExprConfigCacheKey where
@@ -430,6 +452,21 @@ structure Cache where
430452
inferType : InferTypeCache := {}
431453
funInfo : FunInfoCache := {}
432454
synthInstance : SynthInstanceCache := {}
455+
/--
456+
Typeclass queries whose resolution got stuck on a metavariable (`isDefEqStuck`). Such queries
457+
are retried whenever the elaborator makes any progress (see `synthesizeSyntheticMVars`), so
458+
memoizing stuckness lets the retries fail fast instead of re-running the search setup each
459+
time. If the blocking metavariable is assigned in the meantime, the retried query has a
460+
different (more instantiated) key and is not affected by the memoized entry.
461+
462+
Entries are recorded only when stuckness is a pure function of the key and the associated
463+
fingerprint of assignable level metavariables; see `stuckMemoFingerprint?`.
464+
465+
Kept transient (per-`Meta.State`). It is a candidate for metavariable normalization: stuck
466+
queries are metavariable-headed, so normalizing the blocking metavariables could let more
467+
retries share a memoized entry.
468+
-/
469+
synthStuck : PHashMap SynthInstanceCacheKey (Array LMVarId) := {}
433470
whnf : WhnfCache := {}
434471
defEqTrans : DefEqCache := {} -- transient cache for terms containing mvars or using nonstandard configuration options, it is frequently reset.
435472
defEqPerm : DefEqCache := {} -- permanent cache for terms not containing mvars and using standard configuration options
@@ -500,6 +537,17 @@ register_builtin_option maxSynthPendingDepth : Nat := {
500537
descr := "maximum number of nested `synthPending` invocations. When resolving unification constraints, pending type class problems may need to be synthesized. These type class problems may create new unification constraints that again require solving new type class problems. This option puts a threshold on how many nested problems are created."
501538
}
502539

540+
/--
541+
Accumulated `synthPending` decisions of a type class query, used by the type class
542+
resolution cache to bound the `synthPendingDepth` values at which the result may be reused.
543+
See `SynthInstanceCacheEntry.relSynthPendingDepth`.
544+
-/
545+
structure SynthPendingActivity where
546+
/-- Maximum `synthPendingDepth` at which a `synthPending` decision was reached. -/
547+
maxDepth : Option Nat := none
548+
/-- Whether some `synthPending` invocation gave up because of `maxSynthPendingDepth`. -/
549+
guardHit : Bool := false
550+
503551
/--
504552
Contextual information for the `MetaM` monad.
505553
-/
@@ -540,6 +588,15 @@ structure Context where
540588
Remark: `synthPending` fails if `synthPendingDepth > maxSynthPendingDepth`.
541589
-/
542590
synthPendingDepth : Nat := 0
591+
/--
592+
When set, the reference accumulates the `synthPending` decisions reached during the
593+
current type class query, i.e. behavior that may depend on `synthPendingDepth`. The type
594+
class resolution cache uses this to decide at which depths a result may be reused; see
595+
`SynthInstanceCacheKey.synthPendingDepth` and `SynthInstanceCacheEntry.relSynthPendingDepth`.
596+
The reference is intentionally not part of the backtrackable state: a `synthPending`
597+
invocation in a discarded search branch still influenced the search outcome.
598+
-/
599+
synthPendingActivityRef? : Option (IO.Ref SynthPendingActivity) := none
543600
/--
544601
A predicate to control whether a constant can be unfolded or not at `whnf`.
545602
Note that we do not cache results at `whnf` when `canUnfold?` is not `none`. -/
@@ -693,13 +750,13 @@ def resetCache : MetaM Unit :=
693750
modifyCache fun _ => {}
694751

695752
@[inline] def modifyInferTypeCache (f : InferTypeCache → InferTypeCache) : MetaM Unit :=
696-
modifyCache fun ⟨ic, c1, c2, c3, c4, c5⟩ => ⟨f ic, c1, c2, c3, c4, c5⟩
753+
modifyCache fun ⟨ic, c1, c2, c3, c4, c5, c6⟩ => ⟨f ic, c1, c2, c3, c4, c5, c6
697754

698755
@[inline] def modifyDefEqTransientCache (f : DefEqCache → DefEqCache) : MetaM Unit :=
699-
modifyCache fun ⟨c1, c2, c3, c4, defeqTrans, c5⟩ => ⟨c1, c2, c3, c4, f defeqTrans, c5
756+
modifyCache fun ⟨c1, c2, c3, c4, c5, defeqTrans, c6⟩ => ⟨c1, c2, c3, c4, c5, f defeqTrans, c6
700757

701758
@[inline] def modifyDefEqPermCache (f : DefEqCache → DefEqCache) : MetaM Unit :=
702-
modifyCache fun ⟨c1, c2, c3, c4, c5, defeqPerm⟩ => ⟨c1, c2, c3, c4, c5, f defeqPerm⟩
759+
modifyCache fun ⟨c1, c2, c3, c4, c5, c6, defeqPerm⟩ => ⟨c1, c2, c3, c4, c5, c6, f defeqPerm⟩
703760

704761
def mkExprConfigCacheKey (expr : Expr) : MetaM ExprConfigCacheKey :=
705762
return { expr, configKey := (← read).configKey }

0 commit comments

Comments
 (0)