* Move constant registration with elab env from `Lean.addDecl` to `Lean.Environment.addDeclCore` for compatibility * Make module system behavior independent of `Elab.async` value
191 lines
7.5 KiB
Text
191 lines
7.5 KiB
Text
/-
|
|
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
Authors: Leonardo de Moura
|
|
-/
|
|
prelude
|
|
import Lean.CoreM
|
|
import Lean.Namespace
|
|
import Lean.Util.CollectAxioms
|
|
|
|
namespace Lean
|
|
|
|
/-- Adds given declaration to the environment, respecting `debug.skipKernelTC`. -/
|
|
def Kernel.Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
|
(cancelTk? : Option IO.CancelToken := none) : Except Exception Environment :=
|
|
if debug.skipKernelTC.get opts then
|
|
addDeclWithoutChecking env decl
|
|
else
|
|
addDeclCore env (Core.getMaxHeartbeats opts).toUSize decl cancelTk?
|
|
|
|
private def Environment.addDeclAux (env : Environment) (opts : Options) (decl : Declaration)
|
|
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
|
|
env.addDeclCore (Core.getMaxHeartbeats opts).toUSize decl cancelTk? (!debug.skipKernelTC.get opts)
|
|
|
|
@[deprecated "use `Lean.addDecl` instead to ensure new namespaces are registered" (since := "2024-12-03")]
|
|
def Environment.addDecl (env : Environment) (opts : Options) (decl : Declaration)
|
|
(cancelTk? : Option IO.CancelToken := none) : Except Kernel.Exception Environment :=
|
|
Environment.addDeclAux env opts decl cancelTk?
|
|
|
|
private def isNamespaceName : Name → Bool
|
|
| .str .anonymous _ => true
|
|
| .str p _ => isNamespaceName p
|
|
| _ => false
|
|
|
|
private def registerNamePrefixes (env : Environment) (name : Name) : Environment :=
|
|
match name with
|
|
| .str _ s =>
|
|
if s.get 0 == '_' then
|
|
-- Do not register namespaces that only contain internal declarations.
|
|
env
|
|
else
|
|
go env name
|
|
| _ => env
|
|
where go env
|
|
| .str p _ => if isNamespaceName p then go (env.registerNamespace p) p else env
|
|
| _ => env
|
|
|
|
private builtin_initialize privateConstKindsExt : MapDeclarationExtension ConstantKind ←
|
|
mkMapDeclarationExtension
|
|
|
|
/--
|
|
Returns the kind of the declaration as originally declared instead of as exported. This information
|
|
is stored by `Lean.addDecl` and may be inaccurate if that function was circumvented. Returns `none`
|
|
if the declaration was not found.
|
|
-/
|
|
def getOriginalConstKind? (env : Environment) (declName : Name) : Option ConstantKind := do
|
|
privateConstKindsExt.find? env declName <|>
|
|
(env.setExporting false |>.findAsync? declName).map (·.kind)
|
|
|
|
/--
|
|
Checks whether the declaration was originally declared as a theorem; see also
|
|
`Lean.getOriginalConstKind?`. Returns `false` if the declaration was not found.
|
|
-/
|
|
def wasOriginallyTheorem (env : Environment) (declName : Name) : Bool :=
|
|
getOriginalConstKind? env declName |>.map (· matches .thm) |>.getD false
|
|
|
|
-- HACK: remove together with MutualDef HACK when `[dsimp]` is introduced
|
|
private def isSimpleRflProof (proof : Expr) : Bool :=
|
|
if let .lam _ _ proof _ := proof then
|
|
isSimpleRflProof proof
|
|
else
|
|
proof.isAppOfArity ``rfl 2
|
|
|
|
private def looksLikeRelevantTheoremProofType (type : Expr) : Bool :=
|
|
if let .forallE _ _ type _ := type then
|
|
looksLikeRelevantTheoremProofType type
|
|
else
|
|
type.isAppOfArity ``WellFounded 2
|
|
|
|
def addDecl (decl : Declaration) : CoreM Unit := do
|
|
-- register namespaces for newly added constants; this used to be done by the kernel itself
|
|
-- but that is incompatible with moving it to a separate task
|
|
-- NOTE: we do not use `getTopLevelNames` here so that inductive types are registered as
|
|
-- namespaces
|
|
modifyEnv (decl.getNames.foldl registerNamePrefixes)
|
|
|
|
-- convert `Declaration` to `ConstantInfo` to use as a preliminary value in the environment until
|
|
-- kernel checking has finished; not all cases are supported yet
|
|
let mut exportedInfo? := none
|
|
let (name, info, kind) ← match decl with
|
|
| .thmDecl thm =>
|
|
let exportProof := !(← getEnv).header.isModule ||
|
|
-- We should preserve rfl theorems but also we should not override a decision to hide by the
|
|
-- MutualDef elaborator via `withoutExporting`
|
|
(← getEnv).isExporting && isSimpleRflProof thm.value ||
|
|
-- TODO: this is horrible...
|
|
looksLikeRelevantTheoremProofType thm.type
|
|
if !exportProof then
|
|
exportedInfo? := some <| .axiomInfo { thm with isUnsafe := false }
|
|
pure (thm.name, .thmInfo thm, .thm)
|
|
| .defnDecl defn | .mutualDefnDecl [defn] =>
|
|
if (← getEnv).header.isModule && !(← getEnv).isExporting then
|
|
exportedInfo? := some <| .axiomInfo { defn with isUnsafe := defn.safety == .unsafe }
|
|
pure (defn.name, .defnInfo defn, .defn)
|
|
| .axiomDecl ax => pure (ax.name, .axiomInfo ax, .axiom)
|
|
| _ => return (← doAdd)
|
|
|
|
if decl.getTopLevelNames.all isPrivateName then
|
|
exportedInfo? := none
|
|
else
|
|
-- preserve original constant kind in extension if different from exported one
|
|
if exportedInfo?.isSome then
|
|
modifyEnv (privateConstKindsExt.insert · name kind)
|
|
else
|
|
exportedInfo? := some info
|
|
|
|
-- no environment extension changes to report after kernel checking; ensures we do not
|
|
-- accidentally wait for this snapshot when querying extension states
|
|
let env ← getEnv
|
|
let async ← env.addConstAsync (reportExts := false) name kind
|
|
(exportedKind? := exportedInfo?.map (.ofConstantInfo))
|
|
-- report preliminary constant info immediately
|
|
async.commitConst async.asyncEnv (some info) (exportedInfo? <|> info)
|
|
setEnv async.mainEnv
|
|
|
|
let doAddAndCommit := do
|
|
setEnv async.asyncEnv
|
|
try
|
|
doAdd
|
|
finally
|
|
async.commitCheckEnv (← getEnv)
|
|
|
|
if Elab.async.get (← getOptions) then
|
|
let cancelTk ← IO.CancelToken.new
|
|
let checkAct ← Core.wrapAsyncAsSnapshot (cancelTk? := cancelTk) fun _ => doAddAndCommit
|
|
let t ← BaseIO.mapTask checkAct env.checked
|
|
let endRange? := (← getRef).getTailPos?.map fun pos => ⟨pos, pos⟩
|
|
Core.logSnapshotTask { stx? := none, reportingRange? := endRange?, task := t, cancelTk? := cancelTk }
|
|
else
|
|
try
|
|
doAddAndCommit
|
|
finally
|
|
setEnv async.mainEnv
|
|
where
|
|
doAdd := do
|
|
profileitM Exception "type checking" (← getOptions) do
|
|
withTraceNode `Kernel (fun _ => return m!"typechecking declarations {decl.getTopLevelNames}") do
|
|
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
|
logWarning <| .tagged `hasSorry m!"declaration uses 'sorry'"
|
|
try
|
|
let env ← (← getEnv).addDeclAux (← getOptions) decl (← read).cancelTk?
|
|
|> ofExceptKernelException
|
|
setEnv env
|
|
catch ex =>
|
|
-- avoid follow-up errors by (trying to) add broken decl as axiom
|
|
addAsAxiom
|
|
throw ex
|
|
addAsAxiom := do
|
|
-- try to add as axiom with given type for def/theorem
|
|
match decl with
|
|
| .defnDecl d | .thmDecl d =>
|
|
let fallbackDecl := .axiomDecl {
|
|
name := d.name, levelParams := d.levelParams, type := d.type, isUnsafe := false
|
|
}
|
|
try
|
|
let env ← (← getEnv).addDeclAux (← getOptions) fallbackDecl (← read).cancelTk?
|
|
|> ofExceptKernelException
|
|
setEnv env
|
|
return
|
|
catch _ => pure ()
|
|
| _ => pure ()
|
|
|
|
-- otherwise, add as axiom with type `sorry`
|
|
for n in decl.getNames do
|
|
let fallbackDecl := .axiomDecl {
|
|
name := n, levelParams := []
|
|
type := mkApp2 (mkConst ``sorryAx [1]) (mkSort 0) (mkConst ``true), isUnsafe := false
|
|
}
|
|
try
|
|
let env ← (← getEnv).addDeclAux (← getOptions) fallbackDecl (← read).cancelTk?
|
|
|> ofExceptKernelException
|
|
setEnv env
|
|
return
|
|
catch _ => pure ()
|
|
|
|
|
|
def addAndCompile (decl : Declaration) : CoreM Unit := do
|
|
addDecl decl
|
|
compileDecl decl
|
|
|
|
end Lean
|