I wanted to drop a thread here around our experience with making changes to dbg! and the difficulty (I think still unfinished) of getting a consistent experience on the temporary lifetimes. @dianne was already involved so has some additional context, but I thought it'd be a useful point to keep in mind more broadly for this group.
The collection of PRs:
(I may have missed one or two attempts there).
I think this is still pending in #157576 which uses super let to implement it, but as that PR says the result is not great in terms of saying "yes that's doing what I expect".
$(let $bound);+;
$(super let _ = ($bound = $processed));+;
However, the main goal in writing this up is that I think we're missing some good way for us to test this. Most of our temporary lifetimes are inherently implicit, and describing what happens at what scope in a way that can be guaranteed constant across refactoring is hard. Writing tests for language features (e.g., let-else, if-let, ...) takes a good deal of work to remember each case (e.g., see https://github.com/rust-lang/rust/blob/main/tests/ui/let-else/let-else-temporary-lifetime.rs, https://github.com/rust-lang/rust/blob/main/tests/ui/lifetimes/temporary-lifetime-extension.rs). Regardless of the syntax to express (super let, some macros, etc.), I think it would be very useful to have some way to exhaustively cover the cases a macro author (at least) or ideally language feature author needs to concern themselves with.
I'm not sure exactly what form that should take. Maybe the right answer is a collection of macros in core that you need to can use and then assert against a template -- e.g., something like this hypothetical:
temporary_tests!(dbg!($arg1, $arg2));
would expand into something that at least exhaustively enumerates cases and can be snapshot-tested across changes to the internals of the dbg! macro. In principle, that same strategy could be used for a language feature, e.g., something like this?
temporary_tests!(let $pat = $arg1 else { $arg2 });
I've not thought too deeply on the specific semantics, but I suspect the right shape is that each separate case would get its own test case produced from the template. It can then be compared (via execution / Drop prints / something else?) against canonical examples (e.g., "this language feature should behave exactly the same as this alternative feature) or the previous version of a library (snapshot testing) to prevent repeated regressions like the ones we worked through with dbg!.
Cutting an issue per some short discussion with @traviscross offline to keep track of this conversation.
I wanted to drop a thread here around our experience with making changes to
dbg!and the difficulty (I think still unfinished) of getting a consistent experience on the temporary lifetimes. @dianne was already involved so has some additional context, but I thought it'd be a useful point to keep in mind more broadly for this group.The collection of PRs:
dbg!prints #149869 -- this failed with 1.95 beta regression: "temporary value dropped while borrowed" #153850dbg!#154074) then caused 1.96 beta regression: "luadoes not live long enough" #154988 and 1.96 beta regression: "lua does not live long enough", take 2 #155902dbg!, even on false unwind paths #155915, but eventually gave up and just reverted the original change.(I may have missed one or two attempts there).
I think this is still pending in #157576 which uses
super letto implement it, but as that PR says the result is not great in terms of saying "yes that's doing what I expect".However, the main goal in writing this up is that I think we're missing some good way for us to test this. Most of our temporary lifetimes are inherently implicit, and describing what happens at what scope in a way that can be guaranteed constant across refactoring is hard. Writing tests for language features (e.g., let-else, if-let, ...) takes a good deal of work to remember each case (e.g., see https://github.com/rust-lang/rust/blob/main/tests/ui/let-else/let-else-temporary-lifetime.rs, https://github.com/rust-lang/rust/blob/main/tests/ui/lifetimes/temporary-lifetime-extension.rs). Regardless of the syntax to express (
super let, some macros, etc.), I think it would be very useful to have some way to exhaustively cover the cases a macro author (at least) or ideally language feature author needs to concern themselves with.I'm not sure exactly what form that should take. Maybe the right answer is a collection of macros in core that you need to can use and then assert against a template -- e.g., something like this hypothetical:
would expand into something that at least exhaustively enumerates cases and can be snapshot-tested across changes to the internals of the dbg! macro. In principle, that same strategy could be used for a language feature, e.g., something like this?
I've not thought too deeply on the specific semantics, but I suspect the right shape is that each separate case would get its own test case produced from the template. It can then be compared (via execution / Drop prints / something else?) against canonical examples (e.g., "this language feature should behave exactly the same as this alternative feature) or the previous version of a library (snapshot testing) to prevent repeated regressions like the ones we worked through with
dbg!.Cutting an issue per some short discussion with @traviscross offline to keep track of this conversation.