Skip to content
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

Closed
wants to merge 1 commit into from

Conversation

bvanjoi
Copy link
Contributor

@bvanjoi bvanjoi commented Jun 15, 2023

Fixes this comment.

r? @petrochenkov

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 15, 2023
@petrochenkov
Copy link
Contributor

petrochenkov commented Jun 15, 2023

Meta-comment: could you avoid changing and moving code (to compiler/rustc_resolve/src/name_resolution.rs) in a same commit? It makes it harder to review the changes.
Let's start with the changes only, and then the move can be done later in a separate commit (or not done at all).

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Jun 15, 2023

the move can be done later in a separate commit (or not done at all).

The reason I used a segregation file was to hide the non_glob_binding and glob_binding fields. However, I will move them back for a better review process.

@rust-log-analyzer

This comment has been minimized.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Jun 15, 2023

The job x86_64-gnu-tools failed! Check out the build log: (web) (plain)

Click to see the possible cause of the failure (guessed by this bot)

It looks like there is something that is not tested in test/ui that I should fix first

@bvanjoi bvanjoi marked this pull request as draft June 15, 2023 16:00
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@bvanjoi bvanjoi marked this pull request as ready for review June 16, 2023 02:26
@bvanjoi
Copy link
Contributor Author

bvanjoi commented Jun 16, 2023

All tests had passed, @rustbot ready

@petrochenkov
Copy link
Contributor

scopes

@petrochenkov
Copy link
Contributor

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.
In that case errors like GlobVsExpanded would be subsumed by more general errors like MoreExpandedVsOuter (because globs would be an outer scope), ignore_binding would be treated more consistently, and any other ad hoc treatment of non-glob and glob names would be replaced with regular scope walk.

I'm not sure whether non-glob and glob resolutions for the same name should be packed into the same NameResolution, maybe we should have separate module.non_glob_resolutions and module.glob_resolutions instead, that would depend on convenience of implementation.

}

pub(crate) fn non_glob_binding(&self) -> Option<&'a NameBinding<'a>> {
self.non_glob_binding.and_then(|binding| {
Copy link
Contributor

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 })
Copy link
Contributor

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.

Copy link
Contributor Author

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>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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());
Copy link
Contributor

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));
Copy link
Contributor

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?

Copy link
Contributor Author

@bvanjoi bvanjoi Jun 16, 2023

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 {
Copy link
Contributor

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));
Copy link
Contributor

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.
Copy link
Contributor

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()
Copy link
Contributor

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() {}
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No specific problem, it just tests/ui passed after refactoring but block by this comment. So I reduced it and added it into tests/ui after fixed.

btw, It is had some relative with #56593

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 16, 2023
@bvanjoi
Copy link
Contributor Author

bvanjoi commented Jun 16, 2023

it is not exactly what I wanted to do.

Apologize for the misunderstanding on this comment. I just think shaow_glob field to be a hack that should be removed, so I was splitting it into two separate fields.

In that case errors like ....

It appears that simply splitting non-glob-binding and glob-binding fields will not directly solve the problem.

we should have separate module.non_glob_resolutions and module.glob_resolutions

It appears that we may be able to delete the shadow_glob field in NameResolution once we have separated resolver.non_glob_resolution(module) and resolver.glob_resolutions(module). I will investigate this further soon.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Jun 16, 2023

I should clarify that I will not fix these comments temporarily because this refactoring does not appear to address the underlying issue.

@bors
Copy link
Contributor

bors commented Jun 19, 2023

☔ The latest upstream changes (presumably #112774) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Contributor

bors commented Jul 6, 2023

☔ The latest upstream changes (presumably #113391) made this pull request unmergeable. Please resolve the merge conflicts.

@JohnCSimon
Copy link
Member

@bvanjoi

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
@rustbot ready to switch to S-waiting-on-review so the PR is in the reviewer's backlog.

@bvanjoi
Copy link
Contributor Author

bvanjoi commented Aug 27, 2023

No updates for now, I'll look at this after I fix the other issues, so close it for now.

@bvanjoi bvanjoi closed this Aug 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants