Skip to content

Commit e8221dc

Browse files
committed
Edit stdlib flags for stage0 update, refactor to get Verso doc comments, and add a test
1 parent 25b8f5d commit e8221dc

File tree

4 files changed

+73
-30
lines changed

4 files changed

+73
-30
lines changed

src/Init/Notation.lean

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ syntax (name := deprecated) "deprecated" (ppSpace ident)? (ppSpace str)?
634634
(" (" &"since" " := " str ")")? : attr
635635

636636
/--
637-
The attribute `@[suggest_for]` on a declaration suggests likely ways in which
637+
The attribute `@[suggest_for ..]` on a declaration suggests likely ways in which
638638
someone might **incorrectly** refer to a definition.
639639
640640
* `@[suggest_for String.endPos]` on the definition of `String.rawEndPos` suggests that `"str".endPos` might be correctable to `"str".rawEndPos`.
@@ -644,6 +644,10 @@ The namespace of the suggestions is always relative to the root namespace. In th
644644
adding an annotation `@[suggest_for Z.bar]` to `def Z.foo` will suggest `X.Y.Z.foo` only as a
645645
replacement for `Z.foo`. If your intent is to suggest `X.Y.Z.foo` as a replacement for
646646
`X.Y.Z.bar`, you must instead use the annotation `@[suggest_for X.Y.Z.bar]`.
647+
648+
Suggestions can be defined for structure fields or inductive branches with the
649+
`attribute [suggest_for Exception] Except` syntax, and these attributes do not have to be added
650+
in the same module where the actual identifier was defined.
647651
-/
648652
syntax (name := suggest_for) "suggest_for" (ppSpace ident)+ : attr
649653

src/Lean/IdentifierSuggestion.lean

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,46 @@ set_option doc.verso true
1919

2020
public abbrev NameMapExtension := PersistentEnvExtension (Name × Array Name) (Name × Array Name) (NameMap NameSet)
2121

22-
builtin_initialize identifierSuggestionsImpl : NameMapExtension × NameMapExtension ←
23-
-- This is mostly equivalent to a standard `ParametricAttribute` implementation
24-
let existingToIncorrect : NameMapExtension ← registerPersistentEnvExtension {
25-
name := `Lean.identifierSuggestForAttr.existingToIncorrect
26-
mkInitial := pure {},
27-
addImportedFn := fun _ => pure {},
28-
addEntryFn := fun table (trueName, altNames) =>
29-
table.alter trueName fun old =>
30-
altNames.foldl (β := NameSet) (init := old.getD {}) fun accum altName =>
31-
accum.insert altName
32-
exportEntriesFn table :=
33-
table.toArray.map (fun (trueName, altNames) =>(trueName, altNames.toArray))
34-
|>.qsort (lt := fun a b => Name.quickLt a.1 b.1)
35-
}
22+
/--
23+
Create the extension mapping from existing identifiers to the incorrect alternatives for which we
24+
want to provide suggestions. This is mostly equivalent to a {name}`MapDeclarationExtension` or the
25+
extensions underlying {name}`ParametricAttribute` attributes, but it differs in allowing
26+
{name}`suggest_for` attributes to be assigned in files other than the ones where they were defined.
27+
-/
28+
def mkExistingToIncorrect : IO NameMapExtension := registerPersistentEnvExtension {
29+
name := `Lean.identifierSuggestForAttr.existingToIncorrect
30+
mkInitial := pure {},
31+
addImportedFn := fun _ => pure {},
32+
addEntryFn := fun table (trueName, altNames) =>
33+
table.alter trueName fun old =>
34+
altNames.foldl (β := NameSet) (init := old.getD {}) fun accum altName =>
35+
accum.insert altName
36+
exportEntriesFn table :=
37+
table.toArray.map (fun (trueName, altNames) =>(trueName, altNames.toArray))
38+
|>.qsort (lt := fun a b => Name.quickLt a.1 b.1)
39+
}
3640

37-
-- This indexes information the opposite of the way a `ParametricAttribute` does
38-
let incorrectToExisting : NameMapExtension ← registerPersistentEnvExtension {
39-
name := `Lean.identifierSuggestForAttr.incorrectToExisting
40-
mkInitial := pure {},
41-
addImportedFn := fun _ => pure {},
42-
addEntryFn := fun table (trueName, altNames) =>
43-
altNames.foldl (init := table) fun accum altName =>
44-
accum.alter altName fun old =>
45-
old.getD {} |>.insert trueName
46-
exportEntriesFn table :=
47-
table.toArray.map (fun (altName, trueNames) => (altName, trueNames.toArray))
48-
|>.qsort (lt := fun a b => Name.quickLt a.1 b.1)
49-
}
41+
/--
42+
Create the extension mapping incorrect identifiers to the existing identifiers we want to suggest as
43+
replacements. This association is the opposite of the usual mapping for {name}`ParametricAttribute`
44+
attributes.
45+
-/
46+
def mkIncorrectToExisting : IO NameMapExtension := registerPersistentEnvExtension {
47+
name := `Lean.identifierSuggestForAttr.incorrectToExisting
48+
mkInitial := pure {},
49+
addImportedFn := fun _ => pure {},
50+
addEntryFn := fun table (trueName, altNames) =>
51+
altNames.foldl (init := table) fun accum altName =>
52+
accum.alter altName fun old =>
53+
old.getD {} |>.insert trueName
54+
exportEntriesFn table :=
55+
table.toArray.map (fun (altName, trueNames) => (altName, trueNames.toArray))
56+
|>.qsort (lt := fun a b => Name.quickLt a.1 b.1)
57+
}
58+
59+
builtin_initialize identifierSuggestionsImpl : NameMapExtension × NameMapExtension ←
60+
let existingToIncorrect ← mkExistingToIncorrect
61+
let incorrectToExisting ← mkIncorrectToExisting
5062

5163
registerBuiltinAttribute {
5264
name := `suggest_for,
@@ -70,7 +82,7 @@ builtin_initialize identifierSuggestionsImpl : NameMapExtension × NameMapExtens
7082

7183
/--
7284
Given a name, find all the stored correct, existing identifiers that mention that name in a
73-
{lit}`suggest_for` annotation.
85+
{name}`suggest_for` annotation.
7486
-/
7587
public def getSuggestions [Monad m] [MonadEnv m] (incorrectName : Name) : m NameSet := do
7688
let env ← getEnv
@@ -98,7 +110,9 @@ public def getStoredSuggestions [Monad m] [MonadEnv m] (trueName : Name) : m Nam
98110
Throw an unknown constant error message, potentially suggesting alternatives using
99111
{name}`suggest_for` attributes. (Like {name}`throwUnknownConstantAt` but with suggestions.)
100112
101-
The "Unknown constant `<id>`" message will fully qualify the name, whereas the
113+
The replacement will mimic the path structure of the original as much as possible if they share a
114+
path prefix: if there is a suggestion for replacing `Foo.Bar.jazz` with `Foo.Bar.baz`, then
115+
`Bar.jazz` will be replaced by `Bar.baz` unless the resulting constant is ambiguous.
102116
-/
103117
public def throwUnknownConstantWithSuggestions (constName : Name) (ref? : Option Syntax := .none) : CoreM α := do
104118
let suggestions := (← getSuggestions constName).toArray

src/stdlib_flags.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "util/options.h"
22

3+
// this comment has been updated 1 time(s)
34
namespace lean {
45
options get_default_options() {
56
options opts;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
-- test extending suggestions in a different module
2+
3+
/--
4+
error: Invalid field `some`: The environment does not contain `String.some`, so it is not possible to project the field `some` from an expression
5+
x
6+
of type `String`
7+
8+
Hint: Perhaps you meant `String.contains` in place of `String.some`:
9+
.s̵o̵m̵e̵c̲o̲n̲t̲a̲i̲n̲s̲
10+
-/
11+
#guard_msgs in example (x : String) := x.some fun _ => true
12+
13+
attribute [suggest_for String.some] String.any
14+
15+
/--
16+
error: Invalid field `some`: The environment does not contain `String.some`, so it is not possible to project the field `some` from an expression
17+
x
18+
of type `String`
19+
20+
Hint: Perhaps you meant one of these in place of `String.some`:
21+
[apply] `String.contains`
22+
[apply] `String.any`
23+
-/
24+
#guard_msgs in example (x : String) := x.some fun _ => true

0 commit comments

Comments
 (0)