Skip to content

Temporary lifetime testing strategy #159358

Description

@Mark-Simulacrum

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.

Metadata

Metadata

Assignees

Labels

A-temporary-lifetime-extensionArea: temporary lifetime extensionC-discussionCategory: Discussion or questions that doesn't represent real issues.T-langRelevant to the language team

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions