Uh oh!
There was an error while loading. Please reload this page.
Suggestion for 'static impl Trait return - #51444
Conversation
When encountering a named or anonymous sup requirement (for example, `&'a self`) and a `'static` impl Trait return type, suggest adding the `'_` lifetime constraing to the return type.
rust-highfive
commented
Jun 8, 2018
r? @cramertj (rust_highfive has picked a reviewer for you, use r? to override) |
| LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { | ||
| | ----------------------- this return type evaluates to the `'static` lifetime... | ||
| LL | self.x.iter().map(|a| a.0) | ||
| | ------ ^^^^ can't infer an appropriate lifetime |
There was a problem hiding this comment.
Nit: this cant infer an appropriate lifetime hint seems out-of-place to me. it interjects in the middle of the sentence "this return type evaluates to the 'static lifetime but this borrow...". Perhaps move it or combine it somehow with the "can't outlive the anonymous lifetime" error?
There was a problem hiding this comment.
Agree. I tried a couple of different outputs, including:
error: can't infer an appropriate lifetime
--> file.rs:11:16
|
11 | self.x.iter().map(|a| a.0)
| ^^^^ can't infer an appropriate lifetime for this
|
note: this return type evaluates to the `'static` lifetime...
--> file.rs:10:35
|
10 | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...but this borrow...
--> file.rs:11:9
|
11 | self.x.iter().map(|a| a.0)
| ^^^^^^
note: ...can't outlive the anonymous lifetime #1 defined on the method body at 10:5
--> file.rs:10:5
|
10 | / fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
11 | | self.x.iter().map(|a| a.0)
12 | | }
| |_____^
help: you can add a constraint to make the `impl Trait` non`'static` and match the anonymous lifetime #1 defined on the method body at 10:5
|
10 | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I feel that the current output without any primary label would look reasonably good.
There was a problem hiding this comment.
I actually like what you have above, but I think you could remove the "can't infer an appropriate lifetime for this" at the top, since that's covered in the "but this borrow... can't outlive the anonymous lifetime".
There was a problem hiding this comment.
Can you take a look at the current output? I removed the primary label and it does seem slightly easier to read.
| less than `'static` and match {}", | ||
| lifetime, | ||
| ), | ||
| format!("{} + '_", snippet), |
There was a problem hiding this comment.
In the case where the lifetime is named, think it would be more useful to recommend adding a named lifetime here (rather than '_).
There was a problem hiding this comment.
Agree somewhat, the only reason I didn't implement it that way is that from my cursory tests '_ always works, but I could contrive a case where 'a wouldn't. That being said, I can change it if you feel strongly enough (or we could also leave that as a follow up task).
There was a problem hiding this comment.
That makes sense. Thanks for the investigation!
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
estebank
commented
Jun 11, 2018
cc @nikomatsakis you might be interested in providing feedback here too. |
cramertj
commented
Jun 11, 2018
r=me once @nikomatsakis has had a chance to look, too. I still feel strange about recommending |
estebank
commented
Jun 11, 2018
@cramertj I can add the code to do that in the trivial case ( |
cramertj
commented
Jun 11, 2018
@estebank That sounds worth it to me! By " |
estebank
commented
Jun 11, 2018
@cramertj right |
emilyalbini
commented
Jun 18, 2018
estebank
commented
Jun 20, 2018
Ping. |
| ) => { | ||
| let anon_reg_sup = self.is_suitable_region(sup_r)?; | ||
| if sub_r == &RegionKind::ReStatic && | ||
| self._is_return_type_impl_trait(anon_reg_sup.def_id) |
There was a problem hiding this comment.
Nit: We don't normally use method names with a leading _.
| sup_r, | ||
| ) => { | ||
| let anon_reg_sup = self.is_suitable_region(sup_r)?; | ||
| if sub_r == &RegionKind::ReStatic && |
There was a problem hiding this comment.
Are we just concluding that any time that we have a bound of 'static and a fn with an impl Trait return, the two are connected?
e.g., what happens with this example?
use std::fmt::Debug;fnfoo(x:&u32) -> implDebug{let _:&'staticu32 = x;()}There was a problem hiding this comment.
Are we just concluding that any time that we have a bound of 'static and a fn with an impl Trait return, the two are connected?
Close, unless I misunderstand, the code checks that the return type is impl Traitand that it is bound to 'static.
what happens with
The two provided examples keep the current output:
error[E0621]: explicit lifetime required in the type of `x`
--> file.rs:3:25
|
2 | fn foo(x: &u32) -> impl Debug {
| - consider changing the type of `x` to `&'static u32`
3 | let _: &'static u32 = x;
| ^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `x`
--> file.rs:7:29
|
7 | fn bar(x: &u32, y: &u32) -> impl Debug {
| - ^^^^^^^^^^ lifetime `'static` required
| |
| consider changing the type of `x` to `&'static u32`
For the second case, we could expand this code handle it and suggest the following, but it'll be very involved:
fn bar<'a>(x: &'a u32, y: &u32) -> impl Debug + 'a {
x
}
nikomatsakis
commented
Jun 20, 2018
I agree with @cramertj that always suggesting Another related example: use std::fmt::Debug;fnfoo(x:&u32,y:&u32) -> implDebug{
x
}if we suggest |
estebank
commented
Jun 20, 2018
Output for the two samples doesn't change: Now using the lifetime name if available, as reflected in the test: |
emilyalbini
commented
Jun 25, 2018
Ping from triage @nikomatsakis! This PR needs your review. |
nikomatsakis
commented
Jun 25, 2018
Ok, try this example @estebank use std::fmt::Debug;structFoo{}implFoo{fnfoo(&self) -> implDebug{let _:&'staticFoo = self;()}}fnmain(){}I think the reason that this code didn't fire is because a "better" pretty-printed region error was triggering. |
| ) => { | ||
| let anon_reg_sup = self.is_suitable_region(sup_r)?; | ||
| if sub_r == &RegionKind::ReStatic && | ||
| self.is_return_type_impl_trait(anon_reg_sup.def_id) |
There was a problem hiding this comment.
I think that it would be better if we could somehow detect that the 'static was actually coming from the impl trait (as opposed to some other source). One way to do that might be to make use of the sub_origin variable -- but we'd have to update the origin that appears here:
rust/src/librustc/infer/anon_types/mod.rs
Line 367 in b7c6e8f
and maybe here too, though that could come later and is a bit more annoying (since that is an obligation cause). The current values are totally bogus anyway: they claim that impl Trait requirements arise "because returns types must be sized", which is just..not even kind of true.
Anyway, if we added a new SubregionOrigin for "impl trait obligation" and then checked here for that case, I think this would continue to work in the cases that we want, but rule out the cases we don't.
That said, I am not that keen on adding more uses of SubregionOrigin, which is "deprecated" (essentially) in the NLL checker. Still, I'm not sure what better thing to use for now.
estebank
commented
Jun 25, 2018
The output for is |
nikomatsakis
commented
Jun 26, 2018
@estebank huh, ok. Why doesn't your new error message trigger in that case? |
Still checking, but it seems that case is not a It doesn't trigger because it only triggers on I feel pretty comfortable merging this because it is purposely restricted to a specific case which is also a common pitfall for people trying |
nikomatsakis
commented
Jun 27, 2018
OK, I still feel like the test is too broad, but I guess we can wait for someone to report problems to us. |
nikomatsakis
commented
Jun 27, 2018
@bors r+ |
bors
commented
Jun 27, 2018
📌 Commit 612657d has been approved by |
Suggestion for 'static impl Trait return When encountering a named or anonymous sup requirement (for example, `&'a self`) and a `'static` impl Trait return type, suggest adding the `'_` lifetime constraing to the return type. Fix#43719, #51282. ``` error: cannot infer an appropriate lifetime --> $DIR/static-return-lifetime-infered.rs:17:16 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> { | ----------------------- this return type evaluates to the `'static` lifetime... LL | self.x.iter().map(|a| a.0) | ------ ^^^^ | | | ...but this borrow... | note: ...can't outlive the anonymous lifetime #1 defined on the method body at 16:5 --> $DIR/static-return-lifetime-infered.rs:16:5 | LL | / fn iter_values_anon(&self) -> impl Iterator<Item=u32> { LL | | self.x.iter().map(|a| a.0) LL | | } | |_____^ help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 16:5 | LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ```
bors
commented
Jun 28, 2018
bors
commented
Jun 28, 2018
☀️ Test successful - status-appveyor, status-travis |
When encountering a named or anonymous sup requirement (for example,
&'a self) and a'staticimpl Trait return type, suggest adding the'_lifetime constraing to the return type.Fix#43719, #51282.