This PR facilitates augmenting the context of an `InfoTree` with *partial* contexts while elaborating a command. Using partial contexts, this PR also adds support for tracking the parent declaration name of a term in the `InfoTree`. The parent declaration name is needed to compute the call hierarchy in #3082. Specifically, the `Lean.Elab.InfoTree.context` constructor is refactored to take a value of the new type `Lean.Elab.PartialContextInfo` instead of a `Lean.Elab.ContextInfo`, which now refers to a full `InfoTree` context. The `PartialContextInfo` is then merged into a `ContextInfo` while traversing the tree using `Lean.Elab.PartialContextInfo.mergeIntoOuter?`. The partial context after executing `liftTermElabM` is stored in values of a new type `Lean.Elab.CommandContextInfo`. As a result of this, `Lean.Elab.ContextInfo.save` moves to `Lean.Elab.CommandContextInfo.save`. For obtaining the parent declaration for a term, a new typeclass `MonadParentDecl` is introduced to save the parent declaration in `Lean.Elab.withSaveParentDeclInfoContext`. `Lean.Elab.Term.withDeclName x` now calls `withSaveParentDeclInfoContext x` to save the declaration name. ### Migration **The changes to the `InfoTree.context` constructor break backwards compatibility with all downstream users that traverse the `InfoTree` manually instead of going through the functions in `InfoUtils.lean`.** To fix this, you can merge the outer `ContextInfo` in a traversal with the `PartialContextInfo` of an `InfoTree.context` node using `PartialContextInfo.mergeIntoOuter?`. See e.g. `Lean.Elab.InfoTree.foldInfo` for an example: ```lean partial def InfoTree.foldInfo (f : ContextInfo → Info → α → α) (init : α) : InfoTree → α := go none init where go ctx? a | context ctx t => go (ctx.mergeIntoOuter? ctx?) a t | node i ts => let a := match ctx? with | none => a | some ctx => f ctx i a ts.foldl (init := a) (go <| i.updateContext? ctx?) | _ => a ``` Downstream users that manually save `InfoTree`s may need to adjust calls to `ContextInfo.save` to use `CommandContextInfo.save` instead and potentially wrap their `CommandContextInfo` in a `PartialContextInfo.commandCtx` constructor when storing it in an `InfoTree` or `ContextInfo.mk` when creating a full context. ### Motivation As of now, `ContextInfo`s are always *full* contexts, constructed as if they were always created in `liftTermElabM` after running the `TermElabM` action. This is not strictly true; we already create `ContextInfo`s in several places other than `liftTermElabM` and work around the limitation that `ContextInfo`s are always full contexts in certain places (e.g. `Info.updateContext?` is a crux that we need because we can't always create partial contexts at the term-level), but it has mostly worked out so far. Note that one must be very careful when saving a `ContextInfo` in places other than `liftTermElabM` because the context may not be as complete as we would like (e.g. it may lack meta-variable assignments, potentially leading to a language server panic). Unfortunately, the parent declaration of a term is another example of a context that cannot be provided in `liftTermElabM`: The parent declaration is usually set via `withDeclName`, which itself lives in `TermElabM`. So by the time we are trying to save the full `ContextInfo`, the declaration name is already gone. There is no easy fix for this like in the other cases where we would really just like to augment the context with an extra field. The refactor that we decided on to resolve the issue is to refactor the `InfoTree` to take a `PartialContextInfo` instead of a `ContextInfo` and have code that traverses the `InfoTree` merge inner contexts with outer contexts to produce a full `ContextInfo` value. ### Bumps for downstream projects - `lean-pr-testing-3159` branch at Std, not yet opened as a PR - `lean-pr-testing-3159` branch at Mathlib, not yet opened as a PR - https://github.com/leanprover/LeanInk/pull/57 - https://github.com/hargoniX/LeanInk/pull/1 - https://github.com/tydeu/lean4-alloy/pull/7 - https://github.com/leanprover-community/repl/pull/29 --------- Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
109 lines
3.4 KiB
Nix
109 lines
3.4 KiB
Nix
{
|
|
description = "Lean documentation";
|
|
|
|
inputs.lean.url = path:../.;
|
|
inputs.flake-utils.follows = "lean/flake-utils";
|
|
inputs.mdBook = {
|
|
url = "github:leanprover/mdBook";
|
|
flake = false;
|
|
};
|
|
inputs.alectryon = {
|
|
url = "github:Kha/alectryon/typeid";
|
|
flake = false;
|
|
};
|
|
inputs.leanInk = {
|
|
url = "github:leanprover/LeanInk/refs/pull/57/merge";
|
|
flake = false;
|
|
};
|
|
|
|
outputs = inputs@{ self, ... }: inputs.flake-utils.lib.eachDefaultSystem (system:
|
|
with inputs.lean.packages.${system}; with nixpkgs;
|
|
let
|
|
doc-src = lib.sourceByRegex ../. ["doc.*" "tests(/lean(/beginEndAsMacro.lean)?)?"];
|
|
in {
|
|
packages = rec {
|
|
lean-mdbook = mdbook.overrideAttrs (drv: rec {
|
|
name = "lean-${mdbook.name}";
|
|
src = inputs.mdBook;
|
|
cargoDeps = drv.cargoDeps.overrideAttrs (_: {
|
|
inherit src;
|
|
outputHash = "sha256-1YlPS6cqgxE4fjy9G8pWrpP27YrrbCDnfeyIsX81ZNw=";
|
|
});
|
|
doCheck = false;
|
|
});
|
|
book = stdenv.mkDerivation {
|
|
name ="lean-doc";
|
|
src = doc-src;
|
|
buildInputs = [ lean-mdbook ];
|
|
buildCommand = ''
|
|
mkdir $out
|
|
# necessary for `additional-css`...?
|
|
cp -r --no-preserve=mode $src/doc/* .
|
|
# overwrite stub .lean.md files
|
|
cp -r ${inked}/* .
|
|
mdbook build -d $out
|
|
'';
|
|
};
|
|
# We use a separate derivation instead of `checkPhase` so we can push it but not `doc` to the binary cache
|
|
test = stdenv.mkDerivation {
|
|
name ="lean-doc-test";
|
|
src = doc-src;
|
|
buildInputs = [ lean-mdbook stage1.Lean.lean-package strace ];
|
|
patchPhase = ''
|
|
cd doc
|
|
patchShebangs test
|
|
'';
|
|
buildPhase = ''
|
|
mdbook test
|
|
touch $out
|
|
'';
|
|
dontInstall = true;
|
|
};
|
|
leanInk = (buildLeanPackage {
|
|
name = "Main";
|
|
src = inputs.leanInk;
|
|
deps = [ (buildLeanPackage {
|
|
name = "LeanInk";
|
|
src = inputs.leanInk;
|
|
}) ];
|
|
executableName = "leanInk";
|
|
linkFlags = ["-rdynamic"];
|
|
}).executable;
|
|
alectryon = python3Packages.buildPythonApplication {
|
|
name = "alectryon";
|
|
src = inputs.alectryon;
|
|
propagatedBuildInputs =
|
|
[ leanInk lean-all ] ++
|
|
# https://github.com/cpitclaudel/alectryon/blob/master/setup.cfg
|
|
(with python3Packages; [ pygments dominate beautifulsoup4 docutils ]);
|
|
doCheck = false;
|
|
};
|
|
renderLeanMod = mod: mod.overrideAttrs (final: prev: {
|
|
name = "${prev.name}.md";
|
|
buildInputs = prev.buildInputs ++ [ alectryon ];
|
|
outputs = [ "out" ];
|
|
buildCommand = ''
|
|
dir=$(dirname $relpath)
|
|
mkdir -p $dir out/$dir
|
|
if [ -d $src ]; then cp -r $src/. $dir/; else cp $src $leanPath; fi
|
|
alectryon --frontend lean4+markup $leanPath --backend webpage -o $out/$leanPath.md
|
|
'';
|
|
});
|
|
renderPackage = pkg: symlinkJoin {
|
|
name = "${pkg.name}-mds";
|
|
paths = map renderLeanMod (lib.attrValues pkg.mods);
|
|
};
|
|
literate = buildLeanPackage {
|
|
name = "literate";
|
|
src = ./.;
|
|
roots = [
|
|
{ mod = "examples"; glob = "submodules"; }
|
|
{ mod = "monads"; glob = "submodules"; }
|
|
];
|
|
};
|
|
inked = renderPackage literate;
|
|
doc = book;
|
|
};
|
|
defaultPackage = self.packages.${system}.doc;
|
|
});
|
|
}
|