This PR fixes an issue where the use of private imports led to unknown namespaces in downstream modules. Fixes #12833
124 lines
4.5 KiB
Text
124 lines
4.5 KiB
Text
/-
|
||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Std.Data.HashMap.Basic
|
||
public import Lean.Data.PersistentHashMap
|
||
public import Std.Data.HashMap.Iterator
|
||
public import Lean.Data.Iterators.Producers.PersistentHashMap
|
||
public import Init.Data.Iterators.Combinators.Append
|
||
|
||
public section
|
||
universe u v w w'
|
||
|
||
namespace Lean
|
||
|
||
/-- Staged map for implementing the Environment. The idea is to store
|
||
imported entries into a hashtable and local entries into a persistent hashtable.
|
||
|
||
Hypotheses:
|
||
- The number of entries (i.e., declarations) coming from imported files is much bigger than
|
||
the number of entries in the current file.
|
||
- HashMap is faster than PersistentHashMap.
|
||
- When we are reading imported files, we have exclusive access to the map, and efficient
|
||
destructive updates are performed.
|
||
|
||
Remarks:
|
||
- We never remove declarations from the Environment. In principle, we could support
|
||
deletion by using `(PHashMap α (Option β))` where the value `none` would indicate
|
||
that an entry was "removed" from the hashtable.
|
||
- We do not need additional bookkeeping for extracting the local entries.
|
||
-/
|
||
structure SMap (α : Type u) (β : Type v) [BEq α] [Hashable α] where
|
||
stage₁ : Bool := true
|
||
/-- Imported constants. -/
|
||
map₁ : Std.HashMap α β := {}
|
||
/-- Local constants defined in the current module. -/
|
||
map₂ : PHashMap α β := {}
|
||
|
||
namespace SMap
|
||
variable {α : Type u} {β : Type v} [BEq α] [Hashable α]
|
||
|
||
instance : Inhabited (SMap α β) := ⟨{}⟩
|
||
def empty : SMap α β := {}
|
||
|
||
@[inline] def fromHashMap (m : Std.HashMap α β) (stage₁ := true) : SMap α β :=
|
||
{ map₁ := m, stage₁ := stage₁ }
|
||
|
||
@[specialize] def insert : SMap α β → α → β → SMap α β
|
||
| ⟨true, m₁, m₂⟩, k, v => ⟨true, m₁.insert k v, m₂⟩
|
||
| ⟨false, m₁, m₂⟩, k, v => ⟨false, m₁, m₂.insert k v⟩
|
||
|
||
@[specialize] def insert' : SMap α β → α → β → SMap α β
|
||
| ⟨true, m₁, m₂⟩, k, v => ⟨true, m₁.insert k v, m₂⟩
|
||
| ⟨false, m₁, m₂⟩, k, v => ⟨false, m₁, m₂.insert k v⟩
|
||
|
||
@[specialize] def find? : SMap α β → α → Option β
|
||
| ⟨true, m₁, _⟩, k => m₁[k]?
|
||
| ⟨false, m₁, m₂⟩, k => (m₂.find? k).orElse fun _ => m₁[k]?
|
||
|
||
@[inline] def findD (m : SMap α β) (a : α) (b₀ : β) : β :=
|
||
(m.find? a).getD b₀
|
||
|
||
@[inline] def find! [Inhabited β] (m : SMap α β) (a : α) : β :=
|
||
match m.find? a with
|
||
| some b => b
|
||
| none => panic! "key is not in the map"
|
||
|
||
@[specialize] def contains : SMap α β → α → Bool
|
||
| ⟨true, m₁, _⟩, k => m₁.contains k
|
||
| ⟨false, m₁, m₂⟩, k => m₁.contains k || m₂.contains k
|
||
|
||
/-- Similar to `find?`, but searches for result in the hashmap first.
|
||
So, the result is correct only if we never "overwrite" `map₁` entries using `map₂`. -/
|
||
@[specialize] def find?' : SMap α β → α → Option β
|
||
| ⟨true, m₁, _⟩, k => m₁[k]?
|
||
| ⟨false, m₁, m₂⟩, k => m₁[k]?.orElse fun _ => m₂.find? k
|
||
|
||
def forM [Monad m] (s : SMap α β) (f : α → β → m PUnit) : m PUnit := do
|
||
s.map₁.forM f
|
||
s.map₂.forM f
|
||
|
||
instance [Monad m] : ForM m (SMap α β) (α × β) where
|
||
forM s f := forM s fun x y => f (x, y)
|
||
|
||
instance [Monad m] : ForIn m (SMap α β) (α × β) where
|
||
forIn := ForM.forIn
|
||
|
||
def iter (s : SMap α β) :=
|
||
s.map₁.iter.append s.map₂.iter
|
||
|
||
/-- Move from stage 1 into stage 2. -/
|
||
def switch (m : SMap α β) : SMap α β :=
|
||
if m.stage₁ then { m with stage₁ := false } else m
|
||
|
||
@[inline] def foldStage2 {σ : Type w} (f : σ → α → β → σ) (s : σ) (m : SMap α β) : σ :=
|
||
m.map₂.foldl f s
|
||
|
||
/-- Monadic fold over a staged map. -/
|
||
def foldM {m : Type w → Type w'} [Monad m]
|
||
(f : σ → α → β → m σ) (init : σ) (map : SMap α β) : m σ := do
|
||
map.map₂.foldlM f (← map.map₁.foldM f init)
|
||
|
||
def fold {σ : Type w} (f : σ → α → β → σ) (init : σ) (m : SMap α β) : σ :=
|
||
m.map₂.foldl f $ m.map₁.fold f init
|
||
|
||
def numBuckets (m : SMap α β) : Nat :=
|
||
Std.HashMap.Internal.numBuckets m.map₁
|
||
|
||
def toList (m : SMap α β) : List (α × β) :=
|
||
m.fold (init := []) fun es a b => (a, b)::es
|
||
|
||
end SMap
|
||
|
||
def _root_.List.toSMap [BEq α] [Hashable α] (es : List (α × β)) : SMap α β :=
|
||
es.foldl (init := {}) fun s (a, b) => s.insert a b
|
||
|
||
instance {_ : BEq α} {_ : Hashable α} [Repr α] [Repr β] : Repr (SMap α β) where
|
||
reprPrec v prec := Repr.addAppParen (reprArg v.toList ++ ".toSMap") prec
|
||
|
||
end Lean
|