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

resolve: allow super in module in block to refer to block items #79309

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 103 additions & 9 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use crate::diagnostics::Suggestion;
use crate::Determinacy::{self, *};
use crate::Namespace::{self, MacroNS, TypeNS};
use crate::{module_to_string, names_to_string};
use crate::{AllowResolveBlocks, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
use crate::{BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
use crate::{CrateLint, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak};
use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
use crate::{ModuleData, NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};

use rustc_ast::unwrap_or;
use rustc_ast::NodeId;
Expand Down Expand Up @@ -777,13 +777,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let path_res = self.r.resolve_path(
let path_res = self.r.resolve_path_with_ribs(
&import.module_path,
None,
&import.parent_scope,
false,
import.span,
import.crate_lint(),
None,
AllowResolveBlocks::Yes,
);
import.vis.set(orig_vis);

Expand Down Expand Up @@ -818,16 +820,37 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
// For better failure detection, pretend that the import will
// not define any names while resolving its module path.
let orig_vis = import.vis.replace(ty::Visibility::Invisible);
let binding = this.resolve_ident_in_module(
let mut binding = this.resolve_ident_in_module(
module,
source,
ns,
&import.parent_scope,
false,
import.span,
);
import.vis.set(orig_vis);

let mut module = module;
while binding.is_err() {
match module {
ModuleOrUniformRoot::Module(m @ ModuleData { parent: Some(p), .. })
if m.is_block() =>
{
// item not found in opaque block module; try inside module containing the block
module = ModuleOrUniformRoot::Module(*p);
binding = this.resolve_ident_in_module(
module,
source,
ns,
&import.parent_scope,
false,
import.span,
);
}
_ => break,
}
}

import.vis.set(orig_vis);
source_bindings[ns].set(binding);
} else {
return;
Expand Down Expand Up @@ -878,13 +901,15 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
_ => None,
};
let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
let path_res = self.r.resolve_path(
let path_res = self.r.resolve_path_with_ribs(
&import.module_path,
None,
&import.parent_scope,
true,
import.span,
import.crate_lint(),
None,
AllowResolveBlocks::Yes,
);
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
if let Some(orig_unusable_binding) = orig_unusable_binding {
Expand Down Expand Up @@ -1010,14 +1035,36 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
let orig_unusable_binding =
mem::replace(&mut this.unusable_binding, target_bindings[ns].get());
let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
let binding = this.resolve_ident_in_module(
let mut binding = this.resolve_ident_in_module(
module,
ident,
ns,
&import.parent_scope,
true,
import.span,
);

let mut module = module;
while binding.is_err() {
match module {
ModuleOrUniformRoot::Module(m @ ModuleData { parent: Some(p), .. })
if m.is_block() =>
{
// item not found in opaque block module; try inside module containing the block
module = ModuleOrUniformRoot::Module(*p);
binding = this.resolve_ident_in_module(
module,
ident,
ns,
&import.parent_scope,
false,
import.span,
);
}
_ => break,
}
}

this.last_import_segment = orig_last_import_segment;
this.unusable_binding = orig_unusable_binding;
import.vis.set(orig_vis);
Expand Down Expand Up @@ -1323,7 +1370,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
}

fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
let module = match import.imported_module.get().unwrap() {
let mut module = match import.imported_module.get().unwrap() {
ModuleOrUniformRoot::Module(module) => module,
_ => {
self.r.session.span_err(import.span, "cannot glob-import all possible crates");
Expand All @@ -1346,7 +1393,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {

// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
let bindings = self
let mut bindings = self
.r
.resolutions(module)
.borrow()
Expand All @@ -1355,6 +1402,53 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
resolution.borrow().binding().map(|binding| (*key, binding))
})
.collect::<Vec<_>>();

if module.is_block() {
// Glob imports should see "through" an opaque module.
// Prefer items in the opaque module to items in the parent.

let mut imported_items = FxHashSet::default();

while module.is_block() && module.parent.is_some() {
// import these bindings
for (mut key, binding) in bindings {
let scope =
match key.ident.span.reverse_glob_adjust(module.expansion, import.span) {
Some(Some(def)) => self.r.macro_def_scope(def),
Some(None) => import.parent_scope.module,
None => continue,
};
if self.r.is_accessible_from(binding.vis, scope) {
let imported_binding = self.r.import(binding, import);
let _ =
self.r.try_define(import.parent_scope.module, key, imported_binding);
imported_items.insert(key);
}
}

// This was an opaque module; repeat with parent module.
module = module.parent.unwrap();

// Add to module's glob_importers
module.glob_importers.borrow_mut().push(import);

// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
bindings = self
.r
.resolutions(module)
.borrow()
.iter()
.filter_map(|(key, resolution)| {
if imported_items.contains(key) {
return None;
}
resolution.borrow().binding().map(|binding| (*key, binding))
})
.collect::<Vec<_>>();
}
}

for (mut key, binding) in bindings {
let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) {
Some(Some(def)) => self.r.macro_def_scope(def),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
path_span,
crate_lint,
Some(&self.ribs),
crate::AllowResolveBlocks::No,
)
}

Expand Down
22 changes: 19 additions & 3 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#![feature(box_patterns)]
#![feature(bool_to_option)]
#![feature(control_flow_enum)]
#![feature(bindings_after_at)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(nll)]
Expand Down Expand Up @@ -597,6 +598,10 @@ impl<'a> ModuleData<'a> {
matches!(self.kind, ModuleKind::Def(DefKind::Trait, _, _))
}

fn is_block(&self) -> bool {
matches!(self.kind, ModuleKind::Block(_))
}

fn nearest_item_scope(&'a self) -> Module<'a> {
match self.kind {
ModuleKind::Def(DefKind::Enum | DefKind::Trait, ..) => {
Expand Down Expand Up @@ -839,6 +844,13 @@ enum BuiltinMacroState {
AlreadySeen(Span),
}

/// Whether resolve_path_with_ribs may resolve to anonymous block modules
#[derive(Copy, Clone, Debug)]
enum AllowResolveBlocks {
No,
Yes,
}

/// The main resolver class.
///
/// This is the visitor that walks the whole crate.
Expand Down Expand Up @@ -2177,6 +2189,7 @@ impl<'a> Resolver<'a> {
path_span,
crate_lint,
None,
AllowResolveBlocks::No,
)
}

Expand All @@ -2189,6 +2202,7 @@ impl<'a> Resolver<'a> {
path_span: Span,
crate_lint: CrateLint,
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
resolve_opaque: AllowResolveBlocks,
) -> PathResult<'a> {
let mut module = None;
let mut allow_super = true;
Expand Down Expand Up @@ -2231,9 +2245,11 @@ impl<'a> Resolver<'a> {
};
if let Some(self_module) = self_module {
if let Some(parent) = self_module.parent {
module = Some(ModuleOrUniformRoot::Module(
self.resolve_self(&mut ctxt, parent),
));
let resolved = match (resolve_opaque, &parent.kind) {
(AllowResolveBlocks::Yes, ModuleKind::Block(_)) => parent,
_ => self.resolve_self(&mut ctxt, parent),
};
module = Some(ModuleOrUniformRoot::Module(resolved));
continue;
}
}
Expand Down
13 changes: 13 additions & 0 deletions src/test/rustdoc/mod-in-doctest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// compile-flags:--test
// edition:2018

//! ```
//! fn foo() {}
//!
//! mod bar {
//! use super::foo;
//! fn bar() {
//! foo()
//! }
//! }
//! ```
98 changes: 98 additions & 0 deletions src/test/ui/resolve/module-in-block-build-pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// build-pass

const CONST: &str = "OUTER";
fn bar() -> &'static str { "outer" }

fn module_in_function_use_super() {
mod inner {
use super::{bar, CONST};
fn call_bar() {
bar();
}

fn get_const() -> &'static str {
CONST
}
}
}

fn module_in_function_resolve_super() {
mod inner {
fn call_bar() {
super::bar();
}

fn get_const() -> &'static str {
super::CONST
}
}
}


fn module_in_function_use_super_glob() {
mod inner {
use super::*;
fn call_bar() {
bar();
}

fn get_const() -> &'static str {
CONST
}
}
}

fn module_in_block_use_super() {
{
mod inner {
use super::{bar, CONST};
fn call_bar() {
bar();
}

fn get_const() -> &'static str {
CONST
}
}
}
}

fn module_in_block_resolve_super() {
{
mod inner {
fn call_bar() {
super::bar();
}

fn get_const() -> &'static str {
super::CONST
}
}
}
}


fn module_in_block_use_super_glob() {
{
mod inner {
use super::*;
fn call_bar() {
bar();
}

fn get_const() -> &'static str {
CONST
}
}
}
}

fn main() {
module_in_function_use_super();
module_in_function_resolve_super();
module_in_function_use_super_glob();

module_in_block_use_super();
module_in_block_resolve_super();
module_in_block_use_super_glob();
}
12 changes: 12 additions & 0 deletions src/test/ui/resolve/module-in-block-compile-fail.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn module_in_function_cannot_access_variables() {
let x: i32 = 5;

mod inner {
use super::x; //~ ERROR unresolved import `super::x`
fn get_x() -> i32 {
x
}
}
}

fn main() { }
Loading