-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Refactor rustc_resolve::late::lifetimes to resolve per-item #82743
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
Conversation
@@ -97,17 +94,17 @@ impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { | |||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { | |||
match arg.kind { | |||
hir::TyKind::BareFn(_) => { | |||
self.current_index.shift_in(1); | |||
if matches!(self.bound_region, ty::BrAnon(_)) { | |||
// Anonymous regions can't refer across `fn` boundaries |
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 is because BrAnon
s come from an Elision
scope when resolving, which get shadowed when we pass a fn
boundary; BrNamed
regions can refer across fn boundaries though (but we don't need the db index, we can just compare DefId
)
|
||
let named_region_map = krate(tcx); | ||
#[tracing::instrument(level = "debug", skip(tcx))] | ||
fn resolve_lifetimes(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { |
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.
We need to resolve lifetimes per Item
, because of Param
s and ReEarlyBound
s are relevant
@@ -61,6 +50,17 @@ LL | | |||
LL | buzz: Buzz<'a, 'a>, | |||
| | |||
|
|||
error[E0106]: missing lifetime specifier |
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.
Same error is emitted, but now at the end; so, line numbers for errors are no long sequential.
@@ -1,3 +1,18 @@ | |||
warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present |
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.
So...this is actually more correct? We are trying to specially a late-bound lifetime in turbofish. It's just interesting this is now being emitted.
@@ -9,22 +9,6 @@ help: consider introducing a named lifetime parameter | |||
LL | type Item<'a> = IteratorChunk<'a, T, S>; | |||
| ^^^^ ^^^ | |||
|
|||
error: `impl` item signature doesn't match `trait` item signature |
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.
Same thing happens as in no_introducing_in_band_in_locals.rs
.
@@ -1,3 +1,23 @@ | |||
error[E0261]: use of undeclared lifetime name `'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.
Just rearranged. Order makes more sense.
| | ||
LL | fn baz<G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | ||
| - ^^ undeclared lifetime | ||
| | | ||
| help: consider introducing lifetime `'a` here: `'a,` | ||
|
||
error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement |
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.
Just lots of errors gone here. I assume same problem as other two tests: these errors probably get emitted in the wf_checking
bit, which we don't reach because of the first error.
@@ -142,30 +142,6 @@ help: consider using the `'static` lifetime | |||
LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | |||
| ^^^^^^^^^^^^^^^^^ | |||
|
|||
error[E0106]: missing lifetime specifier |
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.
Just rearranged.
So, I'm finding (as I try to use this in #76814) that this doesn't quite do enough, because of cycles. Example:
Basically, I want to be able to ask about So, this is a good start, but still some iteration to do. |
Not sure how strongly it affects this PR, but when lifetime resolution was moved to This would mirror path resolution being performed on AST, and path resolutions being stored in HIR paths, because for named lifetimes the resolution rules are supposed to be exactly the same as for other names. If "per-item" lifetime resolution is done with granularity that is too high, I suspect it would break the "exactly the same as for other names", because type parameters of item |
Yeah, so I think the crux of this is that while lifetime resolution could almost certainly be done in AST, "building up" how you represent those lifetimes in predicates cannot (in part because currently debruijn indices are used, which requires us to not only know what lifetimes are in scope and "usable", but what "level" they sit at; also, because in #76814, we begin to think about the implicit lifetimes in scope from super traits because we have to keep things in order). The
Yeah, so I think this could be a potentially fatal flaw (or at least - until the resolution of named lifetimes moves to AST) with this PR: nested items. Take the following code as an example:
I wanted to do this so that I could avoid another pass in #76814, but it's quite tricky. Still have to experiment a bit. |
5618452
to
51ba5c6
Compare
Okay, after using this in my branch working on #76814, I'm convinced that this PR is necessary. I think eventually we probably want to move named lifetime resolution to ast, like types. But overall I think the rest of lifetime resolution makes sense in hir and it should be fine to do it per item. Additionally, I've included a somewhat-related additional query @petrochenkov did you want to review this? Otherwise, maybe @nikomatsakis? |
|
@cjgillot I've thought about that. And I can't think of a good way to do it so far. Ultimately though, it ends up being a small amount of overall work that gets duplicated, since it's only run for traits, and only for the definition, not the items. |
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 makes a lot of sense to me -- but I am wondering about definition_only
. As far as I can tell, it's only true when we are checking traits, and it's used to skip a bunch of stuff that only seems to apply to functions and things that are not traits. I'd prefer not to have it. =)
@@ -176,6 +174,8 @@ crate struct LifetimeContext<'a, 'tcx> { | |||
|
|||
is_in_const_generic: bool, | |||
|
|||
definition_only: bool, |
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.
Comment!
fn resolve_lifetimes_definition(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> ResolveLifetimes { | ||
do_resolve(tcx, local_def_id, true) | ||
} | ||
|
||
/// Computes the `ResolveLifetimes` map that contains data for the |
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 comment looks out of date, right?
rl | ||
} | ||
|
||
fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ResolveLifetimes { |
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.
Comment!
@@ -392,6 +469,12 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | |||
// We want to nest trait/impl items in their parent, but nothing else. | |||
fn visit_nested_item(&mut self, _: hir::ItemId) {} | |||
|
|||
fn visit_trait_item_ref(&mut self, ii: &'tcx hir::TraitItemRef) { | |||
if !self.definition_only { |
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 we ever want to do this? When we are resolving the trait, definition_only
is true, and I think trait items only appear as the children of a trait, right?
bound at the fn or impl level" | ||
) | ||
.emit(); | ||
if !self.definition_only { |
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 skip this error for traits?
@@ -897,7 +1007,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { | |||
} | |||
|
|||
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { | |||
check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); | |||
if !self.definition_only { |
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.
Again, why skip this for traits?
{ | ||
let _enter = span.enter(); | ||
f(self.scope, &mut this); | ||
if !self.definition_only { |
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 skip this for traits?
@@ -1859,7 +1973,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | |||
} | |||
|
|||
// Check for fn-syntax conflicts with in-band lifetime definitions | |||
if self.is_in_fn_syntax { | |||
if !self.definition_only && self.is_in_fn_syntax { |
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 skip this for traits?
This comment has been minimized.
This comment has been minimized.
5a8ad2a
to
c6ec953
Compare
☔ The latest upstream changes (presumably #82868) made this pull request unmergeable. Please resolve the merge conflicts. |
This reverts commit 22ae20733515d710c1134600bc1e29cdd76f6b9b.
c6ec953
to
cfbd0ee
Compare
Even though we have an upper bound for potential perf regressions from #76814, we are doing slightly more work here, so I'd like to run perf for peace of mind. @bors try @rust-timer queue |
Awaiting bors try build completion. @rustbot label: +S-waiting-on-perf |
⌛ Trying commit cfbd0ee with merge 21a1e699b9e794c09680c90fe7bcf6a375b53f95... |
☀️ Try build successful - checks-actions |
Queued 21a1e699b9e794c09680c90fe7bcf6a375b53f95 with parent f5fe425, future comparison URL. |
Finished benchmarking try commit (21a1e699b9e794c09680c90fe7bcf6a375b53f95): comparison url. Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. Please note that if the perf results are neutral, you should likely undo the rollup=never given below by specifying Importantly, though, if the results of this run are non-neutral do not roll this PR up -- it will mask other regressions or improvements in the roll up. @bors rollup=never |
@bors r+ |
📌 Commit 7cb8f51 has been approved by |
⌛ Testing commit 7cb8f51 with merge e2d2189e07afb2e52b5af38eb607fe44fd64799e... |
This comment has been minimized.
This comment has been minimized.
💔 Test failed - checks-actions |
@bors r=nikomatsakis |
📌 Commit 44e9d20 has been approved by |
☀️ Test successful - checks-actions |
There are some changes to tests that I'd like some feedback on; so this is still WIP.
The reason behind this change will (hopefully) allow us to (as part of #76814) be able to essentially use the lifetime resolve code to resolve all late bound vars (including those of super traits). Currently, it only resolves those that are syntactically in scope. In #76814, I'm essentially finding that I would essentially have to redo the passing of bound vars through scopes (i.e. when instantiating a poly trait ref), and that's what this code does anyways. However, to be able to do this (ask super traits what bound vars are in scope), we have to be able to resolve items separately.
The first commit is actually partially orthogonal. Essentially removing one use of late bound debruijn indices.
Not exactly sure who would be best to review here.
Let r? @nikomatsakis