Zulip Chat Archive

Stream: lean4

Topic: machineApplicableDeprecated tag attribute


Richard Copley (Oct 19 2023 at 23:13):

The comment at the head of Std.CodeAction.Deprecated says

Code action for @[deprecated] replacements

This is an opt-in mechanism for making machine-applicable @[deprecated] definitions. When enabled
(by setting the machineApplicableDeprecated tag attribute), a code action will be triggered
whenever the deprecation lint also fires, allowing the user to replace the usage of the deprecated
constant.

How is "setting the machineApplicableDeprecated tag attribute" done?
In the following example, currently an empty list of code actions is attached to the character range where my_two_pos is used.
[Edt: added import Std.CodeActionDeprecated]

import Init.Data.Nat
import Std.CodeAction.Deprecated

theorem my_zero_lt_two : 0 < 2 := Nat.le_succ _
@[deprecated my_zero_lt_two] theorem my_two_pos : 0 < 2 := my_zero_lt_two
theorem my_two_pow_pos {m : Nat} : 0 < 2 ^ m := Nat.pos_pow_of_pos m my_two_pos

Scott Morrison (Oct 19 2023 at 23:29):

It looks like you haven't imported Std.CodeAction.Deprecated.

Richard Copley (Oct 19 2023 at 23:40):

True! Adding it didn't make the code action appear.

Richard Copley (Oct 20 2023 at 01:26):

"Setting the machineApplicableDeprecated tag attribute" is done by the code of an elaborator, not by a user. The elaborator for alias in Std.Tactic.Alias does it, when there is a @[deprecated] alias x := y and the token deprecated in the attribute tag is not followed by an identifier.

I wonder if this is what was intended:
(1) If a target is provided in a @[deprecated] attribute, the linter sets machineApplicableDeprecated
(2) The alias tactic also sets machineApplicableDeprecated only if it wasn't already done in (1)
... but somehow point (1) didn't get implemented.

import Init.Data.Nat
import Std.CodeAction.Deprecated
import Std.Tactic.Alias

theorem newname : 0 < 2 := Nat.le_succ _
@[deprecated newname] theorem oldname1 : 0 < 2 := newname
@[deprecated newname] alias oldname2 := newname
@[deprecated] alias oldname3 := newname

theorem thm1 {m : Nat} : 0 < 2 ^ m := Nat.pos_pow_of_pos m oldname1 -- `oldname1` gets an empty list of code actions
theorem thm2 {m : Nat} : 0 < 2 ^ m := Nat.pos_pow_of_pos m oldname2 -- `oldname2` gets an empty list of code actions
theorem thm3 {m : Nat} : 0 < 2 ^ m := Nat.pos_pow_of_pos m oldname3 -- `oldname3` gets a code action

Mario Carneiro (Oct 20 2023 at 05:05):

machineApplicableDeprecated is public API but only usable from metaprograms. That is, this is a backend feature which is used for creating tactics and attributes that have support from the code action. The frontend version is @[deprecated] alias, and it is written such that you only get the code action if you use @[deprecated] alias specifically (not @[deprecated other] alias or @[deprecated] def)

Mario Carneiro (Oct 20 2023 at 05:06):

in short, the behavior you demonstrate is deliberate

Mario Carneiro (Oct 20 2023 at 05:08):

When you use @[deprecated a] alias b := c, it is not a machine-applicable replacement because a may not have the same type as c. If you do @[deprecated c] alias b := c then in principle it could do so, but there is not really any reason to write this (maybe we should lint against it?) since it is the same as @[deprecated] alias b := c

Mario Carneiro (Oct 20 2023 at 05:11):

Here's how you are supposed to write the first example:

import Init.Data.Nat
import Std.Tactic.Alias

theorem my_zero_lt_two : 0 < 2 := Nat.le_succ _
@[deprecated] alias my_two_pos := my_zero_lt_two
theorem my_two_pow_pos {m : Nat} : 0 < 2 ^ m := Nat.pos_pow_of_pos m my_two_pos

Richard Copley (Oct 20 2023 at 09:09):

Makes sense! Thank you for the explanation.


Last updated: Dec 20 2023 at 11:08 UTC