Add BuiltinShadowMode

This commit is contained in:
Edwin Cheng 2019-11-30 23:29:21 +08:00
parent 8b278b1ab6
commit bb601e7eaf
7 changed files with 157 additions and 31 deletions

View file

@ -286,7 +286,7 @@ impl SourceAnalyzer {
let items = self
.resolver
.resolve_module_path(db, &path)
.resolve_module_path_in_items(db, &path)
.take_types()
.map(|it| PathResolution::Def(it.into()));
types.or(values).or(items).or_else(|| {

View file

@ -15,7 +15,7 @@ use rustc_hash::FxHashMap;
use crate::{
db::DefDatabase,
expr::{Expr, ExprId, Pat, PatId},
nameres::CrateDefMap,
nameres::{BuiltinShadowMode, CrateDefMap},
path::Path,
src::HasSource,
DefWithBodyId, HasModule, Lookup, ModuleId,
@ -83,7 +83,10 @@ impl Expander {
}
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
self.crate_def_map.resolve_path(db, self.module.local_id, path).0.take_macros()
self.crate_def_map
.resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
.0
.take_macros()
}
}

View file

@ -149,6 +149,16 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
.collect()
});
/// Shadow mode for builtin type
/// Builtin type can be shadowed by same name mode
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BuiltinShadowMode {
// Prefer Module
Module,
// Prefer Other Types
Other,
}
/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
/// Other methods will only resolve values, types and module scoped macros only.
impl ModuleScope {
@ -178,8 +188,20 @@ impl ModuleScope {
}
/// Get a name from current module scope, legacy macros are not included
pub fn get(&self, name: &Name) -> Option<&Resolution> {
self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
pub fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&Resolution> {
match shadow {
BuiltinShadowMode::Module => self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
BuiltinShadowMode::Other => {
let item = self.items.get(name);
if let Some(res) = item {
if let Some(ModuleDefId::ModuleId(_)) = res.def.take_types() {
return BUILTIN_SCOPE.get(name).or(item);
}
}
item.or_else(|| BUILTIN_SCOPE.get(name))
}
}
}
pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
@ -250,8 +272,10 @@ impl CrateDefMap {
db: &impl DefDatabase,
original_module: LocalModuleId,
path: &Path,
shadow: BuiltinShadowMode,
) -> (PerNs, Option<usize>) {
let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
let res =
self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
(res.resolved_def, res.segment_index)
}
}

View file

@ -19,7 +19,7 @@ use crate::{
db::DefDatabase,
nameres::{
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
raw, CrateDefMap, ModuleData, Resolution, ResolveMode,
raw, BuiltinShadowMode, CrateDefMap, ModuleData, Resolution, ResolveMode,
},
path::{Path, PathKind},
per_ns::PerNs,
@ -299,6 +299,7 @@ where
ResolveMode::Import,
module_id,
&import.path,
BuiltinShadowMode::Module,
);
(res.resolved_def, res.reached_fixedpoint)
@ -477,6 +478,7 @@ where
ResolveMode::Other,
*module_id,
path,
BuiltinShadowMode::Module,
);
if let Some(def) = resolved_res.resolved_def.take_macros() {

View file

@ -16,7 +16,7 @@ use test_utils::tested_by;
use crate::{
db::DefDatabase,
nameres::CrateDefMap,
nameres::{BuiltinShadowMode, CrateDefMap},
path::{Path, PathKind},
per_ns::PerNs,
AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
@ -68,8 +68,10 @@ impl CrateDefMap {
mode: ResolveMode,
original_module: LocalModuleId,
path: &Path,
shadow: BuiltinShadowMode,
) -> ResolvePathResult {
let mut segments = path.segments.iter().enumerate();
let mut segments = path.segments.iter().enumerate().peekable();
let mut curr_per_ns: PerNs = match path.kind {
PathKind::DollarCrate(krate) => {
if krate == self.krate {
@ -101,7 +103,11 @@ impl CrateDefMap {
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
self.resolve_name_in_crate_root_or_extern_prelude(
&segment.name,
prefer_module(&mut segments, shadow),
)
}
PathKind::Plain => {
let segment = match segments.next() {
@ -109,7 +115,12 @@ impl CrateDefMap {
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
};
log::debug!("resolving {:?} in module", segment);
self.resolve_name_in_module(db, original_module, &segment.name)
self.resolve_name_in_module(
db,
original_module,
&segment.name,
prefer_module(&mut segments, shadow),
)
}
PathKind::Super => {
if let Some(p) = self.modules[original_module].parent {
@ -139,7 +150,7 @@ impl CrateDefMap {
}
};
for (i, segment) in segments {
while let Some((i, segment)) = segments.next() {
let curr = match curr_per_ns.take_types() {
Some(r) => r,
None => {
@ -160,7 +171,7 @@ impl CrateDefMap {
Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
log::debug!("resolving {:?} in other crate", path);
let defp_map = db.crate_def_map(module.krate);
let (def, s) = defp_map.resolve_path(db, module.local_id, &path);
let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
return ResolvePathResult::with(
def,
ReachedFixedPoint::Yes,
@ -169,7 +180,10 @@ impl CrateDefMap {
}
// Since it is a qualified path here, it should not contains legacy macros
match self[module.local_id].scope.get(&segment.name) {
match self[module.local_id]
.scope
.get(&segment.name, prefer_module(&mut segments, shadow))
{
Some(res) => res.def,
_ => {
log::debug!("path segment {:?} not found", segment.name);
@ -212,7 +226,22 @@ impl CrateDefMap {
}
};
}
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
return ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None);
// if it is not the last segment, we prefer builtin as module
fn prefer_module<I>(
segments: &mut std::iter::Peekable<I>,
shadow: BuiltinShadowMode,
) -> BuiltinShadowMode
where
I: Iterator,
{
if segments.peek().is_some() {
BuiltinShadowMode::Module
} else {
shadow
}
}
}
fn resolve_name_in_module(
@ -220,6 +249,7 @@ impl CrateDefMap {
db: &impl DefDatabase,
module: LocalModuleId,
name: &Name,
shadow: BuiltinShadowMode,
) -> PerNs {
// Resolve in:
// - legacy scope of macro
@ -228,23 +258,33 @@ impl CrateDefMap {
// - std prelude
let from_legacy_macro =
self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
let from_scope =
self[module].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude =
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
let from_prelude = self.resolve_in_prelude(db, name);
let from_prelude = self.resolve_in_prelude(db, name, shadow);
from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
}
fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
fn resolve_name_in_crate_root_or_extern_prelude(
&self,
name: &Name,
shadow: BuiltinShadowMode,
) -> PerNs {
let from_crate_root =
self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
self[self.root].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
from_crate_root.or(from_extern_prelude)
}
fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
fn resolve_in_prelude(
&self,
db: &impl DefDatabase,
name: &Name,
shadow: BuiltinShadowMode,
) -> PerNs {
if let Some(prelude) = self.prelude {
let keep;
let def_map = if prelude.krate == self.krate {
@ -254,7 +294,10 @@ impl CrateDefMap {
keep = db.crate_def_map(prelude.krate);
&keep
};
def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
def_map[prelude.local_id]
.scope
.get(name, shadow)
.map_or_else(PerNs::none, |res| res.def)
} else {
PerNs::none()
}

View file

@ -14,7 +14,7 @@ use crate::{
db::DefDatabase,
expr::{ExprId, PatId},
generics::GenericParams,
nameres::CrateDefMap,
nameres::{BuiltinShadowMode, CrateDefMap},
path::{Path, PathKind},
per_ns::PerNs,
AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
@ -91,7 +91,7 @@ pub enum ValueNs {
impl Resolver {
/// Resolve known trait from std, like `std::futures::Future`
pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> {
let res = self.resolve_module_path(db, path).take_types()?;
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
match res {
ModuleDefId::TraitId(it) => Some(it),
_ => None,
@ -100,7 +100,7 @@ impl Resolver {
/// Resolve known struct from std, like `std::boxed::Box`
pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> {
let res = self.resolve_module_path(db, path).take_types()?;
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
match res {
ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
_ => None,
@ -109,26 +109,34 @@ impl Resolver {
/// Resolve known enum from std, like `std::result::Result`
pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> {
let res = self.resolve_module_path(db, path).take_types()?;
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
match res {
ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
_ => None,
}
}
/// pub only for source-binder
pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
fn resolve_module_path(
&self,
db: &impl DefDatabase,
path: &Path,
shadow: BuiltinShadowMode,
) -> PerNs {
let (item_map, module) = match self.module() {
Some(it) => it,
None => return PerNs::none(),
};
let (module_res, segment_index) = item_map.resolve_path(db, module, path);
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
if segment_index.is_some() {
return PerNs::none();
}
module_res
}
pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
}
pub fn resolve_path_in_type_ns(
&self,
db: &impl DefDatabase,
@ -163,7 +171,12 @@ impl Resolver {
}
}
Scope::ModuleScope(m) => {
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
let (module_def, idx) = m.crate_def_map.resolve_path(
db,
m.module_id,
path,
BuiltinShadowMode::Other,
);
let res = match module_def.take_types()? {
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
@ -256,7 +269,12 @@ impl Resolver {
Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
Scope::ModuleScope(m) => {
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
let (module_def, idx) = m.crate_def_map.resolve_path(
db,
m.module_id,
path,
BuiltinShadowMode::Other,
);
return match idx {
None => {
let value = match module_def.take_values()? {
@ -310,7 +328,7 @@ impl Resolver {
pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
let (item_map, module) = self.module()?;
item_map.resolve_path(db, module, path).0.take_macros()
item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
}
pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {

View file

@ -3641,6 +3641,42 @@ fn main() {
assert_eq!(t, "Foo");
}
#[test]
fn not_shadowing_primitive_by_module() {
let t = type_at(
r#"
//- /str.rs
fn foo() {}
//- /main.rs
mod str;
fn foo() -> &'static str { "" }
fn main() {
foo()<|>;
}"#,
);
assert_eq!(t, "&str");
}
#[test]
fn not_shadowing_module_by_primitive() {
let t = type_at(
r#"
//- /str.rs
fn foo() -> u32 {0}
//- /main.rs
mod str;
fn foo() -> &'static str { "" }
fn main() {
str::foo()<|>;
}"#,
);
assert_eq!(t, "u32");
}
#[test]
fn deref_trait() {
let t = type_at(