-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Point at capture points for non-'static
reference crossing a yield
point
#89734
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement | ||
--> $DIR/type-checking-test-4.rs:43:27 | ||
| | ||
LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { | ||
| ------------ this data with lifetime `'a`... | ||
LL | let y = x as &dyn Bar<'_, '_>; | ||
| - ^^ | ||
| | | ||
| ...is captured here... | ||
LL | | ||
LL | y.get_b(); // ERROR | ||
| - ...and is captured here too | ||
LL | let z = y; | ||
LL | z.get_b() // ERROR | ||
| --------- ...is required to live as long as `'static` here... | ||
| | ||
note: ...and is captured here too | ||
--> $DIR/type-checking-test-4.rs:47:5 | ||
| | ||
LL | z.get_b() // ERROR | ||
| ^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case exemplifies that more Span
wrangling might be needed for perfect output, but the bulk of the logic is ready for review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does this output not have the note for where the 'static
requirement was introduced like the one in the PR description does?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the check for it is quite conservative. I'll see what this case is instead.
Edit: all of these are Subtype
coercion errors, instead of RelateParamBound
:
DEBUG rustc_infer::infer::error_reporting::nice_region_error::static_impl_trait try_report_static_impl_trait(var=EarlyBoundRegion(src/test/ui/traits/trait-upcasting/type-checking-test-4.rs:43:27: 43:29 (#0), "'a"),
-> sub=Subtype(TypeTrace { cause: ObligationCauseData { span: src/test/ui/traits/trait-upcasting/type-checking-test-4.rs:47:5: 47:14 (#0), body_id: HirId { owner: DefId(0:20 ~ type_checking_test_4[7abc]::test_wrong6), local_id: 32 }, code: BlockTailExpression(HirId { owner: DefId(0:20 ~ type_checking_test_4[7abc]::test_wrong6), local_id: 31 }) }, values: Types(ExpectedFound { expected: std::option::Option<&'static u32>, found: std::option::Option<&u32> }) })
ReStatic sup=Subtype(TypeTrace { cause: ObligationCauseData { span: src/test/ui/traits/trait-upcasting/type-checking-test-4.rs:43:13: 43:14 (#0), body_id: HirId { owner: DefId(0:20 ~ type_checking_test_4[7abc]::test_wrong6), local_id: 32 }, code: ImplDerivedObligation(DerivedObligationCause { parent_trait_ref: Binder(<&dyn Foo<'a> as std::ops::CoerceUnsized<_>>, []), parent_code: Coercion { source: &dyn Foo<'a>, target: &dyn Bar<'_, '_> } }) }, values: Types(ExpectedFound { expected: dyn Bar<'_, '_>, found: dyn Bar<'a, 'a> }) }) ReFree(DefId(0:20 ~ type_checking_test_4[7abc]::test_wrong6), BrNamed(DefId(0:21 ~ type_checking_test_4[7abc]::test_wrong6::'a), 'a)))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the ObligationCauseCode is BlockTailExpression, we could safely point at the return type always with a similar label 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check the last commit @BoxyUwU? I think it should address your requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ys i like the note! cool :) not gonna mark this review as revolved though because I seem to have taken over you talking about spans... oops
if let (Constraint::VarSubVar(_, _), SubregionOrigin::DataBorrowed(_, sp)) = | ||
(constraint, origin) | ||
{ | ||
captures.push(*sp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to have specificity to the particular variable this constraint references, and I don't see any filtering on the reporting side. What if these captures were associated with multiple region errors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this code runs in the happy path. Would it make sense to collect these capture regions directly in collect_error_for_expanding_node?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if these captures were associated with multiple region errors?
I mentioned that in the ticket, I'm not entirely sure about how to perform that filtering correctly (I'm not familiar with this part of inference).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The last commit now performs basic filtering based on where the error happened, but it's very naïve (and even then it already changed the output of one test).
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
Show resolved
Hide resolved
error[E0521]: borrowed data escapes outside of associated function | ||
--> $DIR/issue-72312.rs:13:24 | ||
| | ||
LL | pub async fn start(&self) { | ||
| ----- | ||
| | | ||
| `self` is a reference that is only valid in the associated function body | ||
| let's call the lifetime of this reference `'1` | ||
... | ||
LL | require_static(async move { | ||
| ________________________^ | ||
LL | | &self; | ||
LL | | }); | ||
| | ^ | ||
| | | | ||
| |_________`self` escapes the associated function body here | ||
| argument requires that `'1` must outlive `'static` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @oli-obk heads up: would any of your ongoing PRs affect this output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#89229 can affect similar situations, not sure if it affects this very case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it'll be feasible to get this output with nll?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only missing thing would be to point at the source of the 'static
bound, right? I think we can do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interesting thing would be to point at the self
inside the async
block, because if you didn't have that there this could would otherwise work (but we already mention it in the label, so that's fine). Pointing at the 'static
bound would be more important, yes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, for that I think we need to start tracking some extra information in a separate table in borrowck.
I dont know this code so can't really review |
I had a 1:1 with Niko where he had some thoughts, so I'll dump the responsibility on him :) |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good, left some naming nits @estebank
// | ^^^^^ | ||
// | | | ||
// | this data with an anonymous lifetime `'_`... | ||
// | ...is captured here... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this comment rather mystifying. What is about the desugaring that causes that, for example? And what will we do with these variables?
} else { | ||
(!sup_origin.span().overlaps(return_sp), param.param_ty_span) | ||
}; | ||
err.span_label(capture_point, &format!("this data with {}...", lifetime)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe move this above that big scary if
..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving it before won't work because that if affects capture_point
as well.
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
Outdated
Show resolved
Hide resolved
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
Outdated
Show resolved
Hide resolved
@@ -567,7 +569,29 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { | |||
// if this rule starts to create problems we'll | |||
// have to revisit this portion of the code and | |||
// think hard about it. =) -- nikomatsakis | |||
self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); | |||
|
|||
// Obtain the spans for all the capture points for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should call these captures -- but I see what you're doing. You're basically finding, for the variable X that failed, each constraint X: Y
-- i.e., all variables Y that X flows into. I can see why you might call those "captures", but to me that calls to me upvar capture in closures. I'm thinking about other names:
- predecessors: in our graph,
a <: b
(i.e.,b: a
) implies an edgea -> b
. I don't like this name, it's too confusing which is successor and predecessor (and different parts of the code use distinct conventions). - dataflow_targets: you could say that Y is a "dataflow target" of X, which is a term I just made up, but the point is that data from X flows into Y. But we're not capturing the target, we're capturing the constraint.
- influences: these are the constraints that influence the value chosen for X.
- inputs: as above, but even more generic
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like influences.
@@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> { | |||
Region<'tcx>, | |||
SubregionOrigin<'tcx>, | |||
Region<'tcx>, | |||
Vec<Span>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs a comment!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these the "spans" associated with "influencer constraints"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
3e17a3a
to
87df844
Compare
@estebank took a quick look, but I think you're still planning more changes, right? |
I believe the only unaddressed comment is the "mystifying comment". I added that comment to document what the output would be if we didn't do what we're doing there. I don't know how to better explain it, other than outright remove it, and then it will be confusing on why the check is even there 🤔 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me modulo naming nit
@@ -123,56 +125,100 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { | |||
param_name, | |||
lifetime, | |||
); | |||
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); | |||
|
|||
let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let (mention_capture, capture_point) = if sup_origin.span().overlaps(param.param_ty_span) { | |
let (mention_influencer, influencer_point = if sup_origin.span().overlaps(param.param_ty_span) { |
?
…` point ``` error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-72312.rs:10:24 | LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... LL | require_static(async move { | -------------- ...is required to live as long as `'static` here... LL | &self; | ----- ...and is captured here | note: `'static` lifetime requirement introduced by this trait bound --> $DIR/issue-72312.rs:2:22 | LL | fn require_static<T: 'static>(val: T) -> T { | ^^^^^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0759`. ``` Fix rust-lang#72312.
* take diagnostic logic out of happy-path * sort/dedup once * add more comments
87df844
to
40f161a
Compare
@bors r=nikomatsakis |
📌 Commit 40f161a has been approved by |
This comment has been minimized.
This comment has been minimized.
@bors r=nikomatsakis |
📌 Commit d2d9eb3 has been approved by |
🌲 The tree is currently closed for pull requests below priority 100. This pull request will be tested once the tree is reopened. |
Point at capture points for non-`'static` reference crossing a `yield` point ``` error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-72312.rs:10:24 | LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... LL | require_static(async move { | -------------- ...is required to live as long as `'static` here... LL | &self; | ----- ...and is captured here | note: `'static` lifetime requirement introduced by this trait bound --> $DIR/issue-72312.rs:2:22 | LL | fn require_static<T: 'static>(val: T) -> T { | ^^^^^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0759`. ``` Fix rust-lang#72312.
Point at capture points for non-`'static` reference crossing a `yield` point ``` error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/issue-72312.rs:10:24 | LL | pub async fn start(&self) { | ^^^^^ this data with an anonymous lifetime `'_`... ... LL | require_static(async move { | -------------- ...is required to live as long as `'static` here... LL | &self; | ----- ...and is captured here | note: `'static` lifetime requirement introduced by this trait bound --> $DIR/issue-72312.rs:2:22 | LL | fn require_static<T: 'static>(val: T) -> T { | ^^^^^^^ error: aborting due to previous error For more information about this error, try `rustc --explain E0759`. ``` Fix rust-lang#72312.
…askrgr Rollup of 6 pull requests Successful merges: - rust-lang#83174 (Suggest using a temporary variable to fix borrowck errors) - rust-lang#89734 (Point at capture points for non-`'static` reference crossing a `yield` point) - rust-lang#90270 (Make `Borrow` and `BorrowMut` impls `const`) - rust-lang#90741 (Const `Option::cloned`) - rust-lang#91548 (Add spin_loop hint for RISC-V architecture) - rust-lang#91721 (Minor improvements to `future::join!`'s implementation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Fix #72312.