-
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
refactor(resolve): splitting glob and non-glob name bindings #112659
Conversation
Meta-comment: could you avoid changing and moving code (to |
The reason I used a segregation file was to hide the |
This comment has been minimized.
This comment has been minimized.
879073d
to
c4e44c8
Compare
This comment has been minimized.
This comment has been minimized.
c4e44c8
to
b083f8b
Compare
This comment has been minimized.
This comment has been minimized.
b083f8b
to
289b640
Compare
289b640
to
f392f71
Compare
All tests had passed, @rustbot ready |
This PR looks like it is in the right direction, but it is not exactly what I wanted to do. The picture above shows how non-glob and glob names in a module should be integrated into name lookup as two different scopes. I'm not sure whether non-glob and glob resolutions for the same name should be packed into the same |
} | ||
|
||
pub(crate) fn non_glob_binding(&self) -> Option<&'a NameBinding<'a>> { | ||
self.non_glob_binding.and_then(|binding| { |
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.
.and_then(|...| Some(x) )
is .map(|...| x)
None | ||
} | ||
self.non_glob_binding() | ||
.or_else(|| if self.single_imports.is_empty() { self.glob_binding() } else { None }) |
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 logic is likely incorrect and is a source of issues like #56593 (because it doesn't account for macros), but let's keep it as is in this PR.
I'd just want to rename it to something more explanatory, like determinate_binding
, keep the removed comment and add a FIXME.
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, I think that issue #56593 is interesting and could be the next task to work on.
}) | ||
} | ||
|
||
pub(crate) fn add_single_import(&mut self, import: &'a Import<'a>) { | ||
self.single_imports.insert(Interned::new_unchecked(import)); | ||
pub(crate) fn available_binding(&self) -> Option<&'a NameBinding<'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.
pub(crate) fn available_binding(&self) -> Option<&'a NameBinding<'a>> { | |
pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> { |
Assuming the other method is renamed to determinate_binding
.
|
||
pub(crate) fn non_glob_binding(&self) -> Option<&'a NameBinding<'a>> { | ||
self.non_glob_binding.and_then(|binding| { | ||
assert!(!binding.is_glob_import()); |
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'm not sure these asserts are useful, there's literally one place where these fields are assigned and the glob-ness is checked there.
(I guess they could be kept during development and removed before merging.)
resolution.single_imports.remove(&Interned::new_unchecked(import)); | ||
}); | ||
let mut resolution = this.resolution(parent, key).borrow_mut(); | ||
resolution.single_imports.remove(&Interned::new_unchecked(import)); |
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.
update_resolution
has some extra logic related to glob_importers
.
Does it never run in this case? Or it runs but it's irrelevant?
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.
It is a cleanup, because it seems will never meet other logic in update_resolution
because the binding
is not updated, and it will hit following code always:
match resolution.binding() {
_ if old_binding.is_some() => return t,
None => return t,
// xxxxxx
}
Of course, It should revert it back because it is irrelevant.
(false, false) => { | ||
return Err(old_binding); | ||
} | ||
if let Some(old_binding) = resolution.available_binding() && res == Res::Err && old_binding.res() != Res::Err { |
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.
Could you keep the old code structure here when possible?
Otherwise it's hard to see what changes here.
@@ -378,7 +379,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { | |||
if !type_ns_only || ns == TypeNS { | |||
let key = BindingKey::new(target, ns); | |||
let mut resolution = this.resolution(current_module, key).borrow_mut(); | |||
resolution.add_single_import(import); | |||
resolution.single_imports.insert(Interned::new_unchecked(import)); |
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.
Nit: unrelated change, could be moved to a separate cleanup commit.
// If the primary binding is unusable, search further and return the shadowed glob | ||
// binding if it exists. What we really want here is having two separate scopes in | ||
// a module - one for non-globs and one for globs, but until that's done use this | ||
// hack to avoid inconsistent resolution ICEs during import validation. |
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.
Could you keep this comment?
This PR doesn't introduce two separate scopes yet.
@@ -900,7 +895,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { | |||
} | |||
|
|||
// Forbid expanded shadowing to avoid time travel. | |||
if let Some(shadowed_glob) = resolution.shadowed_glob | |||
if let Some(shadowed_glob) = resolution.glob_binding() |
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 line alone looks like a change in semantics - the binding is still glob now, but not necessarily shadowed.
But the binding.res() != shadowed_glob.res()
condition below should ensure the old behavior, right?
pub struct _S(Vec<P>); | ||
} | ||
|
||
fn main() {} |
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.
Is there some specific issue for this test?
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.
Apologize for the misunderstanding on this comment. I just think
It appears that simply splitting
It appears that we may be able to delete the |
I should clarify that I will not fix these comments temporarily because this refactoring does not appear to address the underlying issue. |
☔ The latest upstream changes (presumably #112774) made this pull request unmergeable. Please resolve the merge conflicts. |
☔ The latest upstream changes (presumably #113391) made this pull request unmergeable. Please resolve the merge conflicts. |
ping from triage - can you post your status on this PR? There hasn't been an update in a few months. Thanks! FYI: when a PR is ready for review, send a message containing |
No updates for now, I'll look at this after I fix the other issues, so close it for now. |
Fixes this comment.
r? @petrochenkov