Add BuiltinShadowMode
This commit is contained in:
parent
8b278b1ab6
commit
bb601e7eaf
7 changed files with 157 additions and 31 deletions
|
@ -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(|| {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue