7801: Restrict visibilities to the containing DefMap r=jonas-schievink a=jonas-schievink

Visibilities must always point into the DefMap where they are used, but in a block expression `self` resolves to the *containing* non-block module, which is in a different DefMap. Restrict visibilities accordingly, turning them into basically `pub(block)`, which Rust has no syntax for.

bors r+

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2021-02-28 03:49:40 +00:00 committed by GitHub
commit cbec995822
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 4 deletions

View File

@ -259,3 +259,32 @@ fn main() {
"#]],
);
}
#[test]
fn underscore_import() {
// This used to panic, because the default (private) visibility inside block expressions would
// point into the containing `DefMap`, which visibilities should never be able to do.
mark::check!(adjust_vis_in_block_def_map);
check_at(
r#"
mod m {
fn main() {
use Tr as _;
trait Tr {}
$0
}
}
"#,
expect![[r#"
block scope
_: t
Tr: t
crate
m: t
crate::m
main: v
"#]],
);
}

View File

@ -77,7 +77,7 @@ impl DefMap {
original_module: LocalModuleId,
visibility: &RawVisibility,
) -> Option<Visibility> {
match visibility {
let mut vis = match visibility {
RawVisibility::Module(path) => {
let (result, remaining) =
self.resolve_path(db, original_module, &path, BuiltinShadowMode::Module);
@ -86,15 +86,28 @@ impl DefMap {
}
let types = result.take_types()?;
match types {
ModuleDefId::ModuleId(m) => Some(Visibility::Module(m)),
ModuleDefId::ModuleId(m) => Visibility::Module(m),
_ => {
// error: visibility needs to refer to module
None
return None;
}
}
}
RawVisibility::Public => Some(Visibility::Public),
RawVisibility::Public => Visibility::Public,
};
// In block expressions, `self` normally refers to the containing non-block module, and
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
// DefMap they're written in, so we restrict them when that happens.
if let Visibility::Module(m) = vis {
if self.block_id() != m.block {
mark::hit!(adjust_vis_in_block_def_map);
vis = Visibility::Module(self.module_id(self.root()));
log::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
}
}
Some(vis)
}
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change