feat(Tactic/Alias): let attributes know that the constant is an alias#1763
feat(Tactic/Alias): let attributes know that the constant is an alias#1763JovanGerb wants to merge 5 commits intoleanprover-community:mainfrom
Conversation
|
I wrote this three years ago, adapting Mario's code for the old alias command. Mario insisted that the Yes, the two decisions are incompatible with each other. Interestingly, nothing breaks after your change. However, this doesn't mean there aren't any downstream tools that rely on the current behavior. For prudence, let's have two versions of |
|
All right, I have implemented it as you suggested. Though I would be surprised if anyone was relying on this behaviour. At first I tried to use |
|
I think my implementation of |
|
The precise old behavior is important for some use cases. After digging in some dusty cabinets, I found some tools that use it. They rely on the fact that two aliases are definitionally the same exactly when their root aliases are equal, and two aliases are "iff-siblings" exactly when their root alias names are the same. I think Mario also wanted all aliases to be defined in terms of the root alias. That makes sense for defeq checks, for example, but I think it's more brittle. Anyway, that's not how it's done now and there is no need for that change here. Why don't we have By the way, the names should be |
|
I don't think that there would be any performance bottleneck in What kind of tools are these that rely on the |
|
These tools are for analyzing how aliases are used in practice. For example, I have a As far as cost, recording both is cheap. It will have no significant effect on the alias command since it already did this and each alias declaration is responsible for just one step of root calculation. This is way better than an "incorrect" root alias calculation that is usually O(1)-ish. |
|
I don't think the performance cost is really an issue either way, due to how little this extension is used, an how short the transitive chains are. The cost is more for maintenance. A more complicated environment extensioin will more easily have bugs (especially if the feature is not used), and the |
|
Please tell me more about the relation with |
|
I don't mean that it's really a problem. What |
|
Note that also the original implementation of the transitive closure was not entirely "correct". Because if A is the forward alias of B, B is the forward alias of C, A' is the forward alias of B', and B' is the forward alias of C, then it would not have caught that A and A' were the same. So it feels a bit pointless to restore this behaviour that was already flawed. |
|
I don't understand: a forward alias is always an implication, not an iff. |
|
An implication can have an iff as its conclusion. |
|
Oh! I think you're right, the implementation of |
| /-- Get the transitive alias information for a name -/ | ||
| partial def getRootAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do | ||
| let info? ← getHeadAliasInfo? name | ||
| if let some (.plain n) := info? then | ||
| if let some info ← getRootAliasInfo? n then | ||
| return info | ||
| return info? |
There was a problem hiding this comment.
| /-- Get the transitive alias information for a name -/ | |
| partial def getRootAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do | |
| let info? ← getHeadAliasInfo? name | |
| if let some (.plain n) := info? then | |
| if let some info ← getRootAliasInfo? n then | |
| return info | |
| return info? | |
| /-- Get the old alias information for a name. -/ | |
| partial def getOldAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do | |
| match ← getAliasInfo? name with | |
| | some (.plain n) => getOldAliasInfo? n | |
| | some (.forward n) => | |
| if let some (.plain n') ← getOldAliasInfo? n then | |
| return some (.forward n') | |
| else | |
| return some (.forward n) | |
| | some (.reverse n) => | |
| if let some (.plain n') ← getOldAliasInfo? n then | |
| return some (.reverse n') | |
| else | |
| return some (.reverse n) | |
| | none => return none |
|
|
||
| /-- Get the alias information for a name -/ | ||
| def getAliasInfo [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do | ||
| def getHeadAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do |
There was a problem hiding this comment.
| def getHeadAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do | |
| def getAliasInfo? [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := do |
| return info? | ||
|
|
||
| /-- Get the alias information for a name -/ | ||
| @[deprecated getRootAliasInfo? (since := "2026-04-11")] |
There was a problem hiding this comment.
| @[deprecated getRootAliasInfo? (since := "2026-04-11")] | |
| @[deprecated "use `getAliasInfo?` or `getOldAliasInfo?` for the original behavior" (since := "2026-04-11")] |
| @[deprecated getRootAliasInfo? (since := "2026-04-11")] | ||
| def getAliasInfo [Monad m] [MonadEnv m] (name : Name) : m (Option AliasInfo) := | ||
| getRootAliasInfo? name | ||
|
|
There was a problem hiding this comment.
| /-- Returns the path of aliases starting at a given name. | |
| The return value is a pair `(mps, name)` where `name` is the final non-aliased name in the | |
| alias chain and `mps` is a list of `Bool` indicating the sequence of forward (`true`) and | |
| reverse (`false`) aliases along the chain. | |
| -/ | |
| partial def getAliasPath [Monad m] [MonadEnv m] (name : Name) : m (List Bool × Name) := do | |
| match ← getAliasInfo? name with | |
| | some (.plain name) => getAliasPath name | |
| | some (.forward name) => | |
| let (p, name) ← getAliasPath name | |
| return (true :: p, name) | |
| | some (.reverse name) => | |
| let (p, name) ← getAliasPath name | |
| return (false :: p, name) | |
| | none => return ([], name) |
When tagging an
aliaswithto_additive, we would like to have the translated declaration also be analias, and have it get the docstring that normalaliases get. To do this, we needaliasto first tag the declaration as an alias before elaborating the attributes.I noticed that the
aliasExtextension was not actually storing aliases how they appear, but some funny kind of transitive extension of this. This is annoying, because this is not what is used for the generated docstring. Hence, I've changed this so that the environment extension stores the aliases how they are written down. If desired, it is always possible to compute a transitive closure of this.