From d61d1f2e1ff109a78cf2569d2f6089cd8d128c55 Mon Sep 17 00:00:00 2001 From: "WATGAMER\\snmalton" Date: Thu, 27 Jul 2017 13:39:02 -0400 Subject: [PATCH 1/6] inital RFC commit --- text/0000-warning-on-tautology-else.md | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 text/0000-warning-on-tautology-else.md diff --git a/text/0000-warning-on-tautology-else.md b/text/0000-warning-on-tautology-else.md new file mode 100644 index 00000000000..105043d37ba --- /dev/null +++ b/text/0000-warning-on-tautology-else.md @@ -0,0 +1,60 @@ +- Feature Name: warning_on_tautology_else +- Start Date: 2017-07-27 +- RFC PR: +- Rust Issue: + +# Summary +[summary]: #summary + +When the compiler can statically determine if an if branch will always be `true` or `false` then a compiler warning should be outputted saying something like: `tautology detected else branch unreachable` or `contradiction detected if branch unreachable`. + +# Motivation +[motivation]: #motivation + +The motivation behind this so that the programmer can be told about items that may be logical mistakes. + +# Detailed design +[design]: #detailed-design + +When going through the branch detection if an expression within an if statement is true or if the expression is false within an if or while statement then the warning should be outputted. +Since this is a compiler warning the ability to ignore it should be also allowed so using a macro like `cfg!` does not throw this warning. +So either the compiler should look for the `#[allow]` statement before an if/while statement (which is currently not allowed) or head of where the value is defined. +The former seems like a more intuitive solution because it places the `#[allow]` in the context of where it will apply. + +# How We Teach This +[how-we-teach-this]: #how-we-teach-this + +This can be taught by adding to the books by adding examples like the following which will show the warnings in action. + +```rust +if x > 5 && x < 5 { + call_fn(); +} else { + call_other_fn(); +} + +------------------------------ + +warning: contradiction in if statement, associated block unreachable +1 | / if x > 5 && x < 5 { +2 | | call_fn(); +3 | | } else { +4 | | call_other_fn(); +5 | | } + | |_____^ + | + = note: #[warn(tautology-contradiction)] on by default +``` + +# Drawbacks +[drawbacks]: #drawbacks + +This would require allowing `#[allow]` to be placed before `if` and `while` statements + +# Alternatives +[alternatives]: #alternatives + +The impact of not doing this would be little since it is a warning addition which is currently not present. + +# Unresolved questions +[unresolved]: #unresolved-questions From 368c1f29ba92155275e8c3fc6757ab04c01c50c1 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 5 Apr 2018 18:55:40 -0400 Subject: [PATCH 2/6] Create macro-derive-plop.md --- text/macros-derive-plop.md | 112 +++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 text/macros-derive-plop.md diff --git a/text/macros-derive-plop.md b/text/macros-derive-plop.md new file mode 100644 index 00000000000..c8daba3b536 --- /dev/null +++ b/text/macros-derive-plop.md @@ -0,0 +1,112 @@ +- Feature Name: macros_derive_plop +- Start Date: 2018-03-05 +- RFC PR: (leave this empty) +- Rust Issue: (leave this empty) + +# Summary +[summary]: #summary + +This feature would allow for macros to interact at a block level with surrounding code. However, not all blocks would be able to be interacted with. More specifically, during certain types of controle flows some blocks are only valid when attached to other blocks, these being `else if` and `else` specifically. The goal of this RFC is to allow for macros to "attach" themselves to these other blocks to complete the controle flow syntax. + +# Motivation +[motivation]: #motivation + +The motivation to do this comes from the desire for macros that look more like other blocks of code and for macros that can be optionally extended by external code. + +The first is mostly subjective but if an optional part of the macro was instead defined in an following else block instead of some internal representation then it would be easier for the user or maintainers in the future to understand what was going on with the code. + +The second is the most useful reason to implement this. The current model of macros requires that recursive macros must produce by themselves a fully qualified code block irrespective of where it was called, also the compiler also requires that the surounding code must be also syntactically complete as well. +If there were a few cases where these restrictions were able to be relaxed then it would be possible for macros to have very nice error handling or optional case handling. + +Examples: + +```rust +let handler = dbOpen!{ + ip = address, + username = user, + password = pass +} else { + // handle the case where the connection fails to open +} +``` + +```rust +while! (expr { + // do something +}) else { + // if expr was never true +} +``` + +I have seen somethings like the above wanted in the language but with this RFC such things could be implemented by users instead of going through the RFC process + +# Detailed design +[design]: #detailed-design + +The design of this RFC is meant to work well with either the current `macro_rules!` system or the new Macros2.0 system. But would most likely work the best and look the most like rust if only applied to Macros2.0. + +Proposing two new compiler traits, these being `PlopAhead` and `PlopBehind` where they mean the same sort of thing but on which side of the macro such connection is permitted. + +To add them to a macro it would just `#derive(...)` them. + +Example: + +```rust +#derive(PlopAhead, PlopBehind) +macro foo { + ... +} +``` + +To simplify the description the rest of the design witll be talked about in terms of `Plop` which is generic over either of the actual traits except for the following concerns: +* `PlopAhead` only allows attachment when the macro is ahead of other syntax. Or in other words only attaching to the syntax that follows the macro. +* `PlopBehind` only allows attachment when the macro is behind of other syntax. Or in other words only attaching to the syntax that preceeds the macro. +* When used in combination with one another attachment is allowed on both sides of the macro. + +Even with these traits the requirement that macros must produce fully correct syntax is still present. Macros cannot create dangling blocks or other such things. It does not permit the use of Plop-ing while expanding the macro. + +So what does Ploping allow, it allows for the syntax around a macro to not necessarily be fully legal if the macro was not present. The easiest example would be an `else` statement following a macro. Generally (ie, currently), this is not allowed since an else block is meaningless without a corresponding `if` block. However, if a macro derives `PlopAhead` and after expanding ends with an `if` block then a following `else` would be able to become the `else` for that produced `if`. + +The reason for having two is so that macro creators can more finely control how a macro is used, and so that they don't have to worry about the case which they don't explicitly opt-into. + +For `PlopBehind` such a macro would be able to attach to even a previous keyword. The main example of this would be starting the production with an `if` statement and this would be allowed to then attach to a daginling `else` to form an `else if`. + +This would only be allowed to connect to `if`, `else if`, or `else` statments as they are currently the only blocks that this sort of connection would make sense. + +# How We Teach This +[how-we-teach-this]: #how-we-teach-this + +The reason that I chose `plop` is that the code is connection to other parts of the code and it is a fun word that describes to a reasonable degree of correctness what is happening. + +This is a continuation of existing rust patterns of macros because it allows for more finely controlled use of meta programming. In a sense we are meta programming the meta programming because the use can be extended beyond the macro definition. + +I don't believe that this proposal should change how Rust is taught to new users because the creation of advanced macros is not really a beginner topic. However, when teaching macros it would makes sense to eventually teach it as it is would be a useful tool for some cases of macro creation. + +To teach this feature to existing Rust users the book should be updated to explain the feature. I believe that this would be the best way since the book is a main goto reference of rust programing paradignms. It would also make sense for rust-by-example to get a few examples of how to use it. + +In the sections to do with macros2.0 it would make sense to show that these traits exist and what they do. A couple of examples of how the macros using the traits can interact with other parts of the code. + +An example to show off this feature could be: + +```rust +while! {(expr) { + // do something +}} else { + // if expr was never true +} +``` + +# Drawbacks +[drawbacks]: #drawbacks + +This should not be done because it might expose macros to misuse. It also could make parsing very much harder because syntax could only be rejected after parsing a macro that has these traits to make sure that the macro doesn't make the code correct. + +# Alternatives +[alternatives]: #alternatives + +1. Nothing could be done, the current macro system does work + +# Unresolved questions +[unresolved]: #unresolved-questions + +What parts of the design are still TBD? From bf7d9c362f2b0c69783fac101c8a4d653e382fce Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 5 Apr 2018 18:56:21 -0400 Subject: [PATCH 3/6] Rename --- text/{macros-derive-plop.md => 0000-macros-derive-plop.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename text/{macros-derive-plop.md => 0000-macros-derive-plop.md} (100%) diff --git a/text/macros-derive-plop.md b/text/0000-macros-derive-plop.md similarity index 100% rename from text/macros-derive-plop.md rename to text/0000-macros-derive-plop.md From 5d3467e6ae06c9cc82f30ec20973feb0d781b234 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 5 Apr 2018 18:57:33 -0400 Subject: [PATCH 4/6] Delete rfc from wrong branch --- text/0000-warning-on-tautology-else.md | 60 -------------------------- 1 file changed, 60 deletions(-) delete mode 100644 text/0000-warning-on-tautology-else.md diff --git a/text/0000-warning-on-tautology-else.md b/text/0000-warning-on-tautology-else.md deleted file mode 100644 index 105043d37ba..00000000000 --- a/text/0000-warning-on-tautology-else.md +++ /dev/null @@ -1,60 +0,0 @@ -- Feature Name: warning_on_tautology_else -- Start Date: 2017-07-27 -- RFC PR: -- Rust Issue: - -# Summary -[summary]: #summary - -When the compiler can statically determine if an if branch will always be `true` or `false` then a compiler warning should be outputted saying something like: `tautology detected else branch unreachable` or `contradiction detected if branch unreachable`. - -# Motivation -[motivation]: #motivation - -The motivation behind this so that the programmer can be told about items that may be logical mistakes. - -# Detailed design -[design]: #detailed-design - -When going through the branch detection if an expression within an if statement is true or if the expression is false within an if or while statement then the warning should be outputted. -Since this is a compiler warning the ability to ignore it should be also allowed so using a macro like `cfg!` does not throw this warning. -So either the compiler should look for the `#[allow]` statement before an if/while statement (which is currently not allowed) or head of where the value is defined. -The former seems like a more intuitive solution because it places the `#[allow]` in the context of where it will apply. - -# How We Teach This -[how-we-teach-this]: #how-we-teach-this - -This can be taught by adding to the books by adding examples like the following which will show the warnings in action. - -```rust -if x > 5 && x < 5 { - call_fn(); -} else { - call_other_fn(); -} - ------------------------------- - -warning: contradiction in if statement, associated block unreachable -1 | / if x > 5 && x < 5 { -2 | | call_fn(); -3 | | } else { -4 | | call_other_fn(); -5 | | } - | |_____^ - | - = note: #[warn(tautology-contradiction)] on by default -``` - -# Drawbacks -[drawbacks]: #drawbacks - -This would require allowing `#[allow]` to be placed before `if` and `while` statements - -# Alternatives -[alternatives]: #alternatives - -The impact of not doing this would be little since it is a warning addition which is currently not present. - -# Unresolved questions -[unresolved]: #unresolved-questions From 7e594b155e5fdd2c2387d5a853d15f522d596612 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 5 Apr 2018 18:58:31 -0400 Subject: [PATCH 5/6] Update --- text/0000-macros-derive-plop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0000-macros-derive-plop.md b/text/0000-macros-derive-plop.md index c8daba3b536..e72fa9c7157 100644 --- a/text/0000-macros-derive-plop.md +++ b/text/0000-macros-derive-plop.md @@ -109,4 +109,4 @@ This should not be done because it might expose macros to misuse. It also could # Unresolved questions [unresolved]: #unresolved-questions -What parts of the design are still TBD? + From eb9e0013a2aa89668c8b4e7ab2f1735df44bb8b0 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 6 Apr 2018 09:16:20 -0400 Subject: [PATCH 6/6] Changed the traits to be attributes --- text/0000-macros-derive-plop.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/text/0000-macros-derive-plop.md b/text/0000-macros-derive-plop.md index e72fa9c7157..cb575e13a1e 100644 --- a/text/0000-macros-derive-plop.md +++ b/text/0000-macros-derive-plop.md @@ -45,31 +45,31 @@ I have seen somethings like the above wanted in the language but with this RFC s The design of this RFC is meant to work well with either the current `macro_rules!` system or the new Macros2.0 system. But would most likely work the best and look the most like rust if only applied to Macros2.0. -Proposing two new compiler traits, these being `PlopAhead` and `PlopBehind` where they mean the same sort of thing but on which side of the macro such connection is permitted. +Proposing two new compiler attributes, these being `plopahead` and `plopbehind` where they mean the same sort of thing but on which side of the macro such connection is permitted. -To add them to a macro it would just `#derive(...)` them. +To add them to a macro it would just `#[...]` them. Example: ```rust -#derive(PlopAhead, PlopBehind) +#[plopahead, plopbehind] macro foo { ... } ``` -To simplify the description the rest of the design witll be talked about in terms of `Plop` which is generic over either of the actual traits except for the following concerns: -* `PlopAhead` only allows attachment when the macro is ahead of other syntax. Or in other words only attaching to the syntax that follows the macro. -* `PlopBehind` only allows attachment when the macro is behind of other syntax. Or in other words only attaching to the syntax that preceeds the macro. +To simplify the description the rest of the design witll be talked about in terms of `plop` which is generic over either of the actual traits except for the following concerns: +* `plopahead` only allows attachment when the macro is ahead of other syntax. Or in other words only attaching to the syntax that follows the macro. +* `plopbehind` only allows attachment when the macro is behind of other syntax. Or in other words only attaching to the syntax that preceeds the macro. * When used in combination with one another attachment is allowed on both sides of the macro. Even with these traits the requirement that macros must produce fully correct syntax is still present. Macros cannot create dangling blocks or other such things. It does not permit the use of Plop-ing while expanding the macro. -So what does Ploping allow, it allows for the syntax around a macro to not necessarily be fully legal if the macro was not present. The easiest example would be an `else` statement following a macro. Generally (ie, currently), this is not allowed since an else block is meaningless without a corresponding `if` block. However, if a macro derives `PlopAhead` and after expanding ends with an `if` block then a following `else` would be able to become the `else` for that produced `if`. +So what does Ploping allow, it allows for the syntax around a macro to not necessarily be fully legal if the macro was not present. The easiest example would be an `else` statement following a macro. Generally (ie, currently), this is not allowed since an else block is meaningless without a corresponding `if` block. However, if a macro has the attribute `plopahead` and after expanding ends with an `if` block then a following `else` would be able to become the `else` for that produced `if`. The reason for having two is so that macro creators can more finely control how a macro is used, and so that they don't have to worry about the case which they don't explicitly opt-into. -For `PlopBehind` such a macro would be able to attach to even a previous keyword. The main example of this would be starting the production with an `if` statement and this would be allowed to then attach to a daginling `else` to form an `else if`. +For `plopbehind` such a macro would be able to attach to even a previous keyword. The main example of this would be starting the production with an `if` statement and this would be allowed to then attach to a daginling `else` to form an `else if`. This would only be allowed to connect to `if`, `else if`, or `else` statments as they are currently the only blocks that this sort of connection would make sense.