Skip to content

Commit ec164fb

Browse files
Merge #2455
2455: Add BuiltinShadowMode r=flodiebold a=edwin0cheng This PR try to fix #1905 by introduce an `BuiltinShadowMode` in name resolving functions. cc @flodiebold Co-authored-by: Edwin Cheng <edwin0cheng@gmail.com>
2 parents 780f476 + cfc6e9e commit ec164fb

File tree

7 files changed

+139
-32
lines changed

7 files changed

+139
-32
lines changed

crates/ra_hir/src/source_binder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ impl SourceAnalyzer {
286286

287287
let items = self
288288
.resolver
289-
.resolve_module_path(db, &path)
289+
.resolve_module_path_in_items(db, &path)
290290
.take_types()
291291
.map(|it| PathResolution::Def(it.into()));
292292
types.or(values).or(items).or_else(|| {

crates/ra_hir_def/src/body.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_hash::FxHashMap;
1515
use crate::{
1616
db::DefDatabase,
1717
expr::{Expr, ExprId, Pat, PatId},
18-
nameres::CrateDefMap,
18+
nameres::{BuiltinShadowMode, CrateDefMap},
1919
path::Path,
2020
src::HasSource,
2121
DefWithBodyId, HasModule, Lookup, ModuleId,
@@ -83,7 +83,10 @@ impl Expander {
8383
}
8484

8585
fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
86-
self.crate_def_map.resolve_path(db, self.module.local_id, path).0.take_macros()
86+
self.crate_def_map
87+
.resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
88+
.0
89+
.take_macros()
8790
}
8891
}
8992

crates/ra_hir_def/src/nameres.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
149149
.collect()
150150
});
151151

152+
/// Shadow mode for builtin type which can be shadowed by module.
153+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
154+
pub enum BuiltinShadowMode {
155+
// Prefer Module
156+
Module,
157+
// Prefer Other Types
158+
Other,
159+
}
160+
152161
/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
153162
/// Other methods will only resolve values, types and module scoped macros only.
154163
impl ModuleScope {
@@ -178,8 +187,20 @@ impl ModuleScope {
178187
}
179188

180189
/// Get a name from current module scope, legacy macros are not included
181-
pub fn get(&self, name: &Name) -> Option<&Resolution> {
182-
self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name))
190+
pub fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> Option<&Resolution> {
191+
match shadow {
192+
BuiltinShadowMode::Module => self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)),
193+
BuiltinShadowMode::Other => {
194+
let item = self.items.get(name);
195+
if let Some(res) = item {
196+
if let Some(ModuleDefId::ModuleId(_)) = res.def.take_types() {
197+
return BUILTIN_SCOPE.get(name).or(item);
198+
}
199+
}
200+
201+
item.or_else(|| BUILTIN_SCOPE.get(name))
202+
}
203+
}
183204
}
184205

185206
pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
@@ -250,8 +271,10 @@ impl CrateDefMap {
250271
db: &impl DefDatabase,
251272
original_module: LocalModuleId,
252273
path: &Path,
274+
shadow: BuiltinShadowMode,
253275
) -> (PerNs, Option<usize>) {
254-
let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
276+
let res =
277+
self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
255278
(res.resolved_def, res.segment_index)
256279
}
257280
}

crates/ra_hir_def/src/nameres/collector.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::{
1919
db::DefDatabase,
2020
nameres::{
2121
diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
22-
raw, CrateDefMap, ModuleData, Resolution, ResolveMode,
22+
raw, BuiltinShadowMode, CrateDefMap, ModuleData, Resolution, ResolveMode,
2323
},
2424
path::{Path, PathKind},
2525
per_ns::PerNs,
@@ -299,6 +299,7 @@ where
299299
ResolveMode::Import,
300300
module_id,
301301
&import.path,
302+
BuiltinShadowMode::Module,
302303
);
303304

304305
(res.resolved_def, res.reached_fixedpoint)
@@ -477,6 +478,7 @@ where
477478
ResolveMode::Other,
478479
*module_id,
479480
path,
481+
BuiltinShadowMode::Module,
480482
);
481483

482484
if let Some(def) = resolved_res.resolved_def.take_macros() {

crates/ra_hir_def/src/nameres/path_resolution.rs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use test_utils::tested_by;
1616

1717
use crate::{
1818
db::DefDatabase,
19-
nameres::CrateDefMap,
19+
nameres::{BuiltinShadowMode, CrateDefMap},
2020
path::{Path, PathKind},
2121
per_ns::PerNs,
2222
AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
@@ -68,7 +68,17 @@ impl CrateDefMap {
6868
mode: ResolveMode,
6969
original_module: LocalModuleId,
7070
path: &Path,
71+
shadow: BuiltinShadowMode,
7172
) -> ResolvePathResult {
73+
// if it is not the last segment, we prefer the module to the builtin
74+
let prefer_module = |index| {
75+
if index == path.segments.len() - 1 {
76+
shadow
77+
} else {
78+
BuiltinShadowMode::Module
79+
}
80+
};
81+
7282
let mut segments = path.segments.iter().enumerate();
7383
let mut curr_per_ns: PerNs = match path.kind {
7484
PathKind::DollarCrate(krate) => {
@@ -96,20 +106,20 @@ impl CrateDefMap {
96106
if self.edition == Edition::Edition2015
97107
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
98108
{
99-
let segment = match segments.next() {
100-
Some((_, segment)) => segment,
109+
let (idx, segment) = match segments.next() {
110+
Some((idx, segment)) => (idx, segment),
101111
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
102112
};
103113
log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
104-
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name)
114+
self.resolve_name_in_crate_root_or_extern_prelude(&segment.name, prefer_module(idx))
105115
}
106116
PathKind::Plain => {
107-
let segment = match segments.next() {
108-
Some((_, segment)) => segment,
117+
let (idx, segment) = match segments.next() {
118+
Some((idx, segment)) => (idx, segment),
109119
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
110120
};
111121
log::debug!("resolving {:?} in module", segment);
112-
self.resolve_name_in_module(db, original_module, &segment.name)
122+
self.resolve_name_in_module(db, original_module, &segment.name, prefer_module(idx))
113123
}
114124
PathKind::Super => {
115125
if let Some(p) = self.modules[original_module].parent {
@@ -160,7 +170,7 @@ impl CrateDefMap {
160170
Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ };
161171
log::debug!("resolving {:?} in other crate", path);
162172
let defp_map = db.crate_def_map(module.krate);
163-
let (def, s) = defp_map.resolve_path(db, module.local_id, &path);
173+
let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
164174
return ResolvePathResult::with(
165175
def,
166176
ReachedFixedPoint::Yes,
@@ -169,7 +179,7 @@ impl CrateDefMap {
169179
}
170180

171181
// Since it is a qualified path here, it should not contains legacy macros
172-
match self[module.local_id].scope.get(&segment.name) {
182+
match self[module.local_id].scope.get(&segment.name, prefer_module(i)) {
173183
Some(res) => res.def,
174184
_ => {
175185
log::debug!("path segment {:?} not found", segment.name);
@@ -212,6 +222,7 @@ impl CrateDefMap {
212222
}
213223
};
214224
}
225+
215226
ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
216227
}
217228

@@ -220,6 +231,7 @@ impl CrateDefMap {
220231
db: &impl DefDatabase,
221232
module: LocalModuleId,
222233
name: &Name,
234+
shadow: BuiltinShadowMode,
223235
) -> PerNs {
224236
// Resolve in:
225237
// - legacy scope of macro
@@ -228,23 +240,33 @@ impl CrateDefMap {
228240
// - std prelude
229241
let from_legacy_macro =
230242
self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
231-
let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def);
243+
let from_scope =
244+
self[module].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
232245
let from_extern_prelude =
233246
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
234-
let from_prelude = self.resolve_in_prelude(db, name);
247+
let from_prelude = self.resolve_in_prelude(db, name, shadow);
235248

236249
from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
237250
}
238251

239-
fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs {
252+
fn resolve_name_in_crate_root_or_extern_prelude(
253+
&self,
254+
name: &Name,
255+
shadow: BuiltinShadowMode,
256+
) -> PerNs {
240257
let from_crate_root =
241-
self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def);
258+
self[self.root].scope.get(name, shadow).map_or_else(PerNs::none, |res| res.def);
242259
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
243260

244261
from_crate_root.or(from_extern_prelude)
245262
}
246263

247-
fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs {
264+
fn resolve_in_prelude(
265+
&self,
266+
db: &impl DefDatabase,
267+
name: &Name,
268+
shadow: BuiltinShadowMode,
269+
) -> PerNs {
248270
if let Some(prelude) = self.prelude {
249271
let keep;
250272
let def_map = if prelude.krate == self.krate {
@@ -254,7 +276,10 @@ impl CrateDefMap {
254276
keep = db.crate_def_map(prelude.krate);
255277
&keep
256278
};
257-
def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def)
279+
def_map[prelude.local_id]
280+
.scope
281+
.get(name, shadow)
282+
.map_or_else(PerNs::none, |res| res.def)
258283
} else {
259284
PerNs::none()
260285
}

crates/ra_hir_def/src/resolver.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::{
1414
db::DefDatabase,
1515
expr::{ExprId, PatId},
1616
generics::GenericParams,
17-
nameres::CrateDefMap,
17+
nameres::{BuiltinShadowMode, CrateDefMap},
1818
path::{Path, PathKind},
1919
per_ns::PerNs,
2020
AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
@@ -91,7 +91,7 @@ pub enum ValueNs {
9191
impl Resolver {
9292
/// Resolve known trait from std, like `std::futures::Future`
9393
pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> {
94-
let res = self.resolve_module_path(db, path).take_types()?;
94+
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
9595
match res {
9696
ModuleDefId::TraitId(it) => Some(it),
9797
_ => None,
@@ -100,7 +100,7 @@ impl Resolver {
100100

101101
/// Resolve known struct from std, like `std::boxed::Box`
102102
pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> {
103-
let res = self.resolve_module_path(db, path).take_types()?;
103+
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
104104
match res {
105105
ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
106106
_ => None,
@@ -109,26 +109,34 @@ impl Resolver {
109109

110110
/// Resolve known enum from std, like `std::result::Result`
111111
pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> {
112-
let res = self.resolve_module_path(db, path).take_types()?;
112+
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
113113
match res {
114114
ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
115115
_ => None,
116116
}
117117
}
118118

119-
/// pub only for source-binder
120-
pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
119+
fn resolve_module_path(
120+
&self,
121+
db: &impl DefDatabase,
122+
path: &Path,
123+
shadow: BuiltinShadowMode,
124+
) -> PerNs {
121125
let (item_map, module) = match self.module() {
122126
Some(it) => it,
123127
None => return PerNs::none(),
124128
};
125-
let (module_res, segment_index) = item_map.resolve_path(db, module, path);
129+
let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
126130
if segment_index.is_some() {
127131
return PerNs::none();
128132
}
129133
module_res
130134
}
131135

136+
pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &Path) -> PerNs {
137+
self.resolve_module_path(db, path, BuiltinShadowMode::Module)
138+
}
139+
132140
pub fn resolve_path_in_type_ns(
133141
&self,
134142
db: &impl DefDatabase,
@@ -163,7 +171,12 @@ impl Resolver {
163171
}
164172
}
165173
Scope::ModuleScope(m) => {
166-
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
174+
let (module_def, idx) = m.crate_def_map.resolve_path(
175+
db,
176+
m.module_id,
177+
path,
178+
BuiltinShadowMode::Other,
179+
);
167180
let res = match module_def.take_types()? {
168181
ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
169182
ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
@@ -256,7 +269,12 @@ impl Resolver {
256269
Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
257270

258271
Scope::ModuleScope(m) => {
259-
let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
272+
let (module_def, idx) = m.crate_def_map.resolve_path(
273+
db,
274+
m.module_id,
275+
path,
276+
BuiltinShadowMode::Other,
277+
);
260278
return match idx {
261279
None => {
262280
let value = match module_def.take_values()? {
@@ -310,7 +328,7 @@ impl Resolver {
310328

311329
pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> {
312330
let (item_map, module) = self.module()?;
313-
item_map.resolve_path(db, module, path).0.take_macros()
331+
item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
314332
}
315333

316334
pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {

crates/ra_hir_ty/src/tests.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3693,6 +3693,42 @@ fn main() {
36933693
assert_eq!(t, "Foo");
36943694
}
36953695

3696+
#[test]
3697+
fn not_shadowing_primitive_by_module() {
3698+
let t = type_at(
3699+
r#"
3700+
//- /str.rs
3701+
fn foo() {}
3702+
3703+
//- /main.rs
3704+
mod str;
3705+
fn foo() -> &'static str { "" }
3706+
3707+
fn main() {
3708+
foo()<|>;
3709+
}"#,
3710+
);
3711+
assert_eq!(t, "&str");
3712+
}
3713+
3714+
#[test]
3715+
fn not_shadowing_module_by_primitive() {
3716+
let t = type_at(
3717+
r#"
3718+
//- /str.rs
3719+
fn foo() -> u32 {0}
3720+
3721+
//- /main.rs
3722+
mod str;
3723+
fn foo() -> &'static str { "" }
3724+
3725+
fn main() {
3726+
str::foo()<|>;
3727+
}"#,
3728+
);
3729+
assert_eq!(t, "u32");
3730+
}
3731+
36963732
#[test]
36973733
fn deref_trait() {
36983734
let t = type_at(

0 commit comments

Comments
 (0)