Open
Labels
T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Description
In https://crater-reports.s3.amazonaws.com/beta-1.63-2/beta-2022-07-16/reg/cabot-0.7.1/log.txt, it looks like the stderr() temporary isn't living long enough with the changes after #96455. However, I've not actually bisected or investigated thoroughly to confirm this -- it seems likely that this is the expected breakage noted in the FCP comment here (#96455 (comment)), though.
cc @dtolnay
Metadata
Metadata
Assignees
Labels
T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Activity
dtolnay commentedon Jul 24, 2022
Yeah this would be #96455; it's the "needs_late_drop" due to "custom signature for write_fmt" situation described in #96455 (comment).
https://docs.rs/async-std/latest/async_std/io/prelude/trait.WriteExt.html#method.write_fmt
IMO this signature obviously doesn't fit the "contrived" characterization I made about custom write_fmt signatures in that comment, so I think it would be reasonable to revert to late drop for the writer argument of
write!andwriteln!to support this, while keeping early drop for only the format arguments (to still avoid all the cases from #96434).@rust-lang/libs-api
dtolnay commentedon Jul 24, 2022
Sadly I think that combination might be impossible to implement (from a brief attempt) and we'll end up forced to drop the format args of
write!andwriteln!late as well.dtolnay commentedon Jul 24, 2022
Some nonworking implementations:
dtolnay commentedon Jul 24, 2022
I put up a revert for now in #99689.
eddyb commentedon Jul 27, 2022
Hmm,
|args: $crate::fmt::Arguments<'_>| $dst.write_fmt(args)obviously doesn't work because$dstcan be an arbitrarily expression, but I believe that the intended meaning is equivalent to$dst.write_fmt, if we allowed using that syntax to automatically create a closure for the method call, after evaluating$dst(tho that's still not great because one could have a field with that name anyway, which could take precedence over this hypothetical feature).eddyb commentedon Jul 27, 2022
If autoref is all that's needed to make
$dstdrop later than the format args, it can be done:(playground link)
A type parameter could be used instead of a
constgeneric, but then you need a sealedtraitto bound it, and frankly they're equivalent and we could pick based on compilation performance (if there's even a noticeable difference between them).For completeness, I believe the
autoref!macro above would allow:dtolnay commentedon Jul 27, 2022
@eddyb I tried coding up your suggestion (ddaa6e7b498e81ca93a667e7ebdbca677d048a50) but it failed
x.py installwith code like this:In the T-lang zulip I floated the idea of
receiver.fn methodnamefor partial function application of a receiver, as illustrated by this:Then:
NLL would need to know that $dst is not mutably borrowed until
write_fmtis called, so we are free to do immutable access in between$dst.fn write_fmtand the call.If we ever end up doing qualified paths in method syntax (
thing.std::io::Write::write(&buffer)) then something like$dst.<_>::write_fmtmay mesh better than$dst.fn write_fmt. That unambiguously refers to a methodwrite_fmt.You mentioned "just make
$dst.write_fmtwork", but I suspect that isn't going to fly because we already intentionally distinguish naming fields from naming methods in the syntax, e.g. to "call" a field you're required to write(thing.field)()as opposed to justthing.field(). It would be out of character forthing.fieldto be "whichever one exists".joshtriplett commentedon Jul 27, 2022
@dtolnay If the language had `let autoref = ..., would that help? (We've talked about that in @rust-lang/lang.)
joshtriplett commentedon Jul 27, 2022
Meanwhile, applying the revert seems fine as a fix for now.
dtolnay commentedon Jul 27, 2022
Yes Josh, I believe that could be defined in such a way as to work here. It'd be:
but it potentially gets weirder with borrowchecking than hypothetical
receiver.fn methodnamedoes, in particular to support:$dst can't turn into an exclusive reference "too early".
eddyb commentedon Jul 28, 2022
Yeah, I almost suggested something like
k#autorefbinding modifiers, but it won't do you much more good than.autoref_mut()(where all of the complexity goes into ensuring that method resolution actually finds the right autoref helper, and not some user-controlled impostor)But that worst-case example is an example of "two-phase borrows" (aka 2Φ), so really you'd want:
cc @rust-lang/wg-nll (Personally I prefer if a low-level perma-unstable tool like this was explicit about the powers it tapped into, but maybe it's not that huge of a deal?)
Rollup merge of rust-lang#99689 - dtolnay:write, r=Mark-Simulacrum
danielhenrymantilla commentedon Aug 5, 2022
Note that there was some more discussion about this over Zulip.
My personal short-term solution, here, barring two-phased borrows, would be to have a helper extension method to take care of the necessary autoref, thence yielding the following key macro rule:
See the post in question for more info.
Retro-compatiblity with two-phased borrow
Seems to be the remaining thorny point:
how much breakage stems from that?
in the aforementioned post, some hacky workarounds could allow not breaking the current usages which rely on it, I guess, although it's hard to assess without actual evidence of what kind of code breaks when we don't have it.
eddyb commentedon Aug 6, 2022
@danielhenrymantilla Isn't that just like my earlier suggestion in #99684 (comment), except without the protection from users defining e.g. inherent
__by_refmethods that would end up with higher priority than the one the macro intends to call?danielhenrymantilla commentedon Aug 6, 2022
@eddyb yeah, totally1, sorry for the redundant suggestion 🙇, I somehow scrolled past your post.
so, would the suggested workaround tackle the remainging two-phased borrows failures?
EDIT: I've decided to go ahead and test this idea using Fix #99684 through autoref in
write!macro with a two-phased borrows retrocompat workaround #100202Footnotes
I had left the part where we make
by_refmore robust to clashes for a later stage, since we know it's doable (and withopaque/ def_site hygiene, it would even be trivial) ↩Mark-Simulacrum commentedon Aug 7, 2022
Untagging as a regression since we merged a revert (#99689) in #100171. Not closing since it sounds like we're still investigating some alternative fixes for future releases.