@@ -429,27 +429,27 @@ private abbrev getUnifyKeyArgs (e : Expr) (root : Bool) : MetaM (Key × Array Ex
429429private def getStarResult (d : DiscrTree α) : Array α :=
430430 let result : Array α := .mkEmpty initCapacity
431431 match d.root.find? .star with
432- | none => result
433- | some (.node vs _) => result ++ vs
432+ | none => result
433+ | some t => result ++ getValues t
434434
435435private abbrev findKey (cs : Array (Key × Trie α)) (k : Key) : Option (Key × Trie α) :=
436436 cs.binSearch (k, default) (fun a b => a.1 < b.1 )
437437
438438private partial def getMatchLoop (todo : Array Expr) (c : Trie α) (result : Array α) : MetaM (Array α) := do
439- match c with
440- | .node vs cs =>
441- if todo.isEmpty then
442- return result ++ vs
443- else if cs.isEmpty then
444- return result
445- else
439+ if todo.isEmpty then
440+ return result ++ getValues c
441+ else
442+ match c with
443+ | .empty => return result
444+ | .values _ t => getMatchLoop todo t result
445+ | .branch cs =>
446+ if cs.isEmpty then return result else -- should not happen
446447 let e := todo.back!
447448 let todo := todo.pop
448449 let first := cs[0 ]! /- Recall that `Key.star` is the minimal key -/
449- let (k, args) ← getMatchKeyArgs e (root := false )
450450 /- We must always visit `Key.star` edges since they are wildcards.
451- Thus, `todo` is not used linearly when there is `Key.star` edge
452- and there is an edge for `k` and `k != Key.star`. -/
451+ Thus, `todo` is not used linearly when there is `Key.star` edge
452+ and there is an edge for `k` and `k != Key.star`. -/
453453 let visitStar (result : Array α) : MetaM (Array α) :=
454454 if first.1 == .star then
455455 getMatchLoop todo first.2 result
@@ -459,10 +459,38 @@ private partial def getMatchLoop (todo : Array Expr) (c : Trie α) (result : Arr
459459 match findKey cs k with
460460 | none => return result
461461 | some c => getMatchLoop (todo ++ args) c.2 result
462+ let (k, args) ← getMatchKeyArgs e (root := false )
462463 let result ← visitStar result
463464 match k with
464465 | .star => return result
465466 | _ => visitNonStar k args result
467+ | .path ks t =>
468+ let rec loop (todo : Array Expr) (result : Array α) (i : Nat) : MetaM (Array α) := do
469+ -- the following logic is a copy of the .branch case, as if `cs` is a singleton
470+ if h : i < ks.size then
471+ if todo.isEmpty then
472+ return result
473+ let e := todo.back!
474+ let todo := todo.pop
475+ let k' := ks[i]
476+ let visitStar (result : Array α) : MetaM (Array α) :=
477+ if k' == .star then
478+ loop todo result (i + 1 )
479+ else
480+ return result
481+ let visitNonStar (k : Key) (args : Array Expr) (result : Array α) : MetaM (Array α) :=
482+ if k == k' then
483+ loop (todo ++ args) result (i + 1 )
484+ else
485+ return result
486+ let (k, args) ← getMatchKeyArgs e (root := false )
487+ let result ← visitStar result
488+ match k with
489+ | .star => return result
490+ | _ => visitNonStar k args result
491+ else
492+ getMatchLoop todo t result
493+ loop todo result 0
466494
467495private def getMatchRoot (d : DiscrTree α) (k : Key) (args : Array Expr) (result : Array α) : MetaM (Array α) :=
468496 match d.root.find? k with
@@ -544,8 +572,11 @@ private partial def getAllValuesForKey (d : DiscrTree α) (k : Key) (result : Ar
544572where
545573 go (trie : Trie α) (result : Array α) : Array α := Id.run do
546574 match trie with
547- | .node vs cs =>
548- let mut result := result ++ vs
575+ | .empty => return result
576+ | .values vs t => go t (result ++ vs)
577+ | .path _ t => go t result
578+ | .branch cs =>
579+ let mut result := result
549580 for (_, trie) in cs do
550581 result := go trie result
551582 return result
@@ -576,33 +607,66 @@ partial def getUnify (d : DiscrTree α) (e : Expr) : MetaM (Array α) :=
576607 | some c => process 0 args c result
577608where
578609 process (skip : Nat) (todo : Array Expr) (c : Trie α) (result : Array α) : MetaM (Array α) := do
579- match skip, c with
580- | skip+1 , .node _ cs =>
581- if cs.isEmpty then
582- return result
583- else
584- cs.foldlM (init := result) fun result ⟨k, c⟩ => process (skip + k.arity) todo c result
585- | 0 , .node vs cs => do
586- if todo.isEmpty then
587- return result ++ vs
588- else if cs.isEmpty then
589- return result
590- else
591- let e := todo.back!
592- let todo := todo.pop
593- let (k, args) ← getUnifyKeyArgs e (root := false )
594- let visitStar (result : Array α) : MetaM (Array α) :=
595- let first := cs[0 ]!
596- if first.1 == .star then
597- process 0 todo first.2 result
598- else
610+ if skip == 0 && todo.isEmpty then
611+ return result ++ getValues c
612+ else match c with
613+ | .empty => return result
614+ | .values _ t => process skip todo t result
615+ | .branch cs =>
616+ match skip with
617+ | skip+1 =>
618+ if cs.isEmpty then
599619 return result
600- let visitNonStar (k : Key) (args : Array Expr) (result : Array α) : MetaM (Array α) :=
601- match findKey cs k with
602- | none => return result
603- | some c => process 0 (todo ++ args) c.2 result
604- match k with
605- | .star => cs.foldlM (init := result) fun result ⟨k, c⟩ => process k.arity todo c result
606- | _ => visitNonStar k args (← visitStar result)
620+ else
621+ cs.foldlM (init := result) fun result ⟨k, c⟩ => process (skip + k.arity) todo c result
622+ | 0 => do
623+ if cs.isEmpty then return result else -- should not happen
624+ let e := todo.back!
625+ let todo := todo.pop
626+ let (k, args) ← getUnifyKeyArgs e (root := false )
627+ let visitStar (result : Array α) : MetaM (Array α) :=
628+ let first := cs[0 ]!
629+ if first.1 == .star then
630+ process 0 todo first.2 result
631+ else
632+ return result
633+ let visitNonStar (k : Key) (args : Array Expr) (result : Array α) : MetaM (Array α) :=
634+ match findKey cs k with
635+ | none => return result
636+ | some c => process 0 (todo ++ args) c.2 result
637+ match k with
638+ | .star => cs.foldlM (init := result) fun result ⟨k, c⟩ => process k.arity todo c result
639+ | _ => visitNonStar k args (← visitStar result)
640+ | .path ks t =>
641+ let rec loop (skip : Nat) (todo : Array Expr) (result : Array α) (i : Nat) : MetaM (Array α) :=
642+ if h : i < ks.size then
643+ match skip with
644+ | skip+1 =>
645+ let k' := ks[i]
646+ loop (skip + k'.arity) todo result (i + 1 )
647+ | 0 => do
648+ if todo.isEmpty then
649+ return result
650+ else
651+ let e := todo.back!
652+ let todo := todo.pop
653+ let k' := ks[i]
654+ let visitStar (result : Array α) : MetaM (Array α) :=
655+ if k' == .star then
656+ loop 0 todo result (i + 1 )
657+ else
658+ return result
659+ let visitNonStar (k : Key) (args : Array Expr) (result : Array α) : MetaM (Array α) :=
660+ if k' == k then
661+ loop 0 (todo ++ args) result (i + 1 )
662+ else
663+ return result
664+ let (k, args) ← getUnifyKeyArgs e (root := false )
665+ match k with
666+ | .star => loop k'.arity todo result (i + 1 )
667+ | _ => visitNonStar k args (← visitStar result)
668+ else
669+ process skip todo t result
670+ loop skip todo result 0
607671
608672end Lean.Meta.DiscrTree
0 commit comments