Skip to content

Commit 9a7fd6f

Browse files
authored
Merge pull request rust-lang#18422 from ChayimFriedman2/cursed-name-res
fix: Properly resolve prelude paths inside modules inside blocks
2 parents 003270d + 709805a commit 9a7fd6f

File tree

2 files changed

+180
-52
lines changed

2 files changed

+180
-52
lines changed

src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs

+155-52
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//!
1111
//! `ReachedFixedPoint` signals about this.
1212
13+
use either::Either;
1314
use hir_expand::{name::Name, Lookup};
1415
use span::Edition;
1516
use triomphe::Arc;
@@ -150,17 +151,8 @@ impl DefMap {
150151

151152
let mut arc;
152153
let mut current_map = self;
153-
loop {
154-
let new = current_map.resolve_path_fp_with_macro_single(
155-
db,
156-
mode,
157-
original_module,
158-
path,
159-
shadow,
160-
expected_macro_subns,
161-
);
162154

163-
// Merge `new` into `result`.
155+
let mut merge = |new: ResolvePathResult| {
164156
result.resolved_def = result.resolved_def.or(new.resolved_def);
165157
if result.reached_fixedpoint == ReachedFixedPoint::No {
166158
result.reached_fixedpoint = new.reached_fixedpoint;
@@ -171,7 +163,9 @@ impl DefMap {
171163
(Some(old), Some(new)) => Some(old.max(new)),
172164
(None, new) => new,
173165
};
166+
};
174167

168+
loop {
175169
match current_map.block {
176170
Some(block) if original_module == Self::ROOT => {
177171
// Block modules "inherit" names from its parent module.
@@ -180,8 +174,38 @@ impl DefMap {
180174
current_map = &arc;
181175
}
182176
// Proper (non-block) modules, including those in block `DefMap`s, don't.
183-
_ => return result,
177+
_ => {
178+
if original_module != Self::ROOT && current_map.block.is_some() {
179+
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
180+
// the prelude items (which are not inserted into blocks because they can be overridden there).
181+
original_module = Self::ROOT;
182+
arc = db.crate_def_map(self.krate);
183+
current_map = &arc;
184+
185+
let new = current_map.resolve_path_fp_in_all_preludes(
186+
db,
187+
mode,
188+
original_module,
189+
path,
190+
shadow,
191+
);
192+
merge(new);
193+
}
194+
195+
return result;
196+
}
184197
}
198+
199+
let new = current_map.resolve_path_fp_with_macro_single(
200+
db,
201+
mode,
202+
original_module,
203+
path,
204+
shadow,
205+
expected_macro_subns,
206+
);
207+
208+
merge(new);
185209
}
186210
}
187211

@@ -195,7 +219,7 @@ impl DefMap {
195219
expected_macro_subns: Option<MacroSubNs>,
196220
) -> ResolvePathResult {
197221
let mut segments = path.segments().iter().enumerate();
198-
let mut curr_per_ns = match path.kind {
222+
let curr_per_ns = match path.kind {
199223
PathKind::DollarCrate(krate) => {
200224
if krate == self.krate {
201225
cov_mark::hit!(macro_dollar_crate_self);
@@ -296,25 +320,96 @@ impl DefMap {
296320

297321
PerNs::types(module.into(), Visibility::Public, None)
298322
}
299-
PathKind::Abs => {
300-
// 2018-style absolute path -- only extern prelude
301-
let segment = match segments.next() {
302-
Some((_, segment)) => segment,
323+
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
324+
Either::Left(it) => it,
325+
Either::Right(reached_fixed_point) => {
326+
return ResolvePathResult::empty(reached_fixed_point)
327+
}
328+
},
329+
};
330+
331+
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
332+
}
333+
334+
/// Resolves a path only in the preludes, without accounting for item scopes.
335+
pub(super) fn resolve_path_fp_in_all_preludes(
336+
&self,
337+
db: &dyn DefDatabase,
338+
mode: ResolveMode,
339+
original_module: LocalModuleId,
340+
path: &ModPath,
341+
shadow: BuiltinShadowMode,
342+
) -> ResolvePathResult {
343+
let mut segments = path.segments().iter().enumerate();
344+
let curr_per_ns = match path.kind {
345+
// plain import or absolute path in 2015: crate-relative with
346+
// fallback to extern prelude (with the simplification in
347+
// rust-lang/rust#57745)
348+
// FIXME there must be a nicer way to write this condition
349+
PathKind::Plain | PathKind::Abs
350+
if self.data.edition == Edition::Edition2015
351+
&& (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
352+
{
353+
let (_, segment) = match segments.next() {
354+
Some((idx, segment)) => (idx, segment),
303355
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
304356
};
305-
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
306-
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
307-
PerNs::types(
308-
def.into(),
309-
Visibility::Public,
310-
extern_crate.map(ImportOrExternCrate::ExternCrate),
311-
)
312-
} else {
313-
return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
357+
tracing::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
358+
self.resolve_name_in_extern_prelude(segment)
359+
}
360+
PathKind::Plain => {
361+
let (_, segment) = match segments.next() {
362+
Some((idx, segment)) => (idx, segment),
363+
None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
364+
};
365+
tracing::debug!("resolving {:?} in module", segment);
366+
self.resolve_name_in_all_preludes(db, segment)
367+
}
368+
PathKind::Abs => match self.resolve_path_abs(&mut segments, path) {
369+
Either::Left(it) => it,
370+
Either::Right(reached_fixed_point) => {
371+
return ResolvePathResult::empty(reached_fixed_point)
314372
}
373+
},
374+
PathKind::DollarCrate(_) | PathKind::Crate | PathKind::Super(_) => {
375+
return ResolvePathResult::empty(ReachedFixedPoint::Yes)
315376
}
316377
};
317378

379+
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
380+
}
381+
382+
/// 2018-style absolute path -- only extern prelude
383+
fn resolve_path_abs<'a>(
384+
&self,
385+
segments: &mut impl Iterator<Item = (usize, &'a Name)>,
386+
path: &ModPath,
387+
) -> Either<PerNs, ReachedFixedPoint> {
388+
let segment = match segments.next() {
389+
Some((_, segment)) => segment,
390+
None => return Either::Right(ReachedFixedPoint::Yes),
391+
};
392+
if let Some(&(def, extern_crate)) = self.data.extern_prelude.get(segment) {
393+
tracing::debug!("absolute path {:?} resolved to crate {:?}", path, def);
394+
Either::Left(PerNs::types(
395+
def.into(),
396+
Visibility::Public,
397+
extern_crate.map(ImportOrExternCrate::ExternCrate),
398+
))
399+
} else {
400+
Either::Right(ReachedFixedPoint::No) // extern crate declarations can add to the extern prelude
401+
}
402+
}
403+
404+
fn resolve_remaining_segments<'a>(
405+
&self,
406+
segments: impl Iterator<Item = (usize, &'a Name)>,
407+
mut curr_per_ns: PerNs,
408+
path: &ModPath,
409+
db: &dyn DefDatabase,
410+
shadow: BuiltinShadowMode,
411+
original_module: LocalModuleId,
412+
) -> ResolvePathResult {
318413
for (i, segment) in segments {
319414
let (curr, vis, imp) = match curr_per_ns.take_types_full() {
320415
Some(r) => r,
@@ -475,24 +570,9 @@ impl DefMap {
475570
// they might been shadowed by local names.
476571
return PerNs::none();
477572
}
478-
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
479-
PerNs::types(
480-
it.into(),
481-
Visibility::Public,
482-
extern_crate.map(ImportOrExternCrate::ExternCrate),
483-
)
484-
})
485-
};
486-
let macro_use_prelude = || {
487-
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
488-
PerNs::macros(
489-
it,
490-
Visibility::Public,
491-
// FIXME?
492-
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
493-
)
494-
})
573+
self.resolve_name_in_extern_prelude(name)
495574
};
575+
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
496576
let prelude = || {
497577
if self.block.is_some() && module == DefMap::ROOT {
498578
return PerNs::none();
@@ -507,6 +587,38 @@ impl DefMap {
507587
.or_else(prelude)
508588
}
509589

590+
fn resolve_name_in_all_preludes(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
591+
// Resolve in:
592+
// - extern prelude / macro_use prelude
593+
// - std prelude
594+
let extern_prelude = self.resolve_name_in_extern_prelude(name);
595+
let macro_use_prelude = || self.resolve_in_macro_use_prelude(name);
596+
let prelude = || self.resolve_in_prelude(db, name);
597+
598+
extern_prelude.or_else(macro_use_prelude).or_else(prelude)
599+
}
600+
601+
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs {
602+
self.data.extern_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| {
603+
PerNs::types(
604+
it.into(),
605+
Visibility::Public,
606+
extern_crate.map(ImportOrExternCrate::ExternCrate),
607+
)
608+
})
609+
}
610+
611+
fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs {
612+
self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| {
613+
PerNs::macros(
614+
it,
615+
Visibility::Public,
616+
// FIXME?
617+
None, // extern_crate.map(ImportOrExternCrate::ExternCrate),
618+
)
619+
})
620+
}
621+
510622
fn resolve_name_in_crate_root_or_extern_prelude(
511623
&self,
512624
db: &dyn DefDatabase,
@@ -525,16 +637,7 @@ impl DefMap {
525637
// Don't resolve extern prelude in pseudo-module of a block.
526638
return PerNs::none();
527639
}
528-
self.data.extern_prelude.get(name).copied().map_or(
529-
PerNs::none(),
530-
|(it, extern_crate)| {
531-
PerNs::types(
532-
it.into(),
533-
Visibility::Public,
534-
extern_crate.map(ImportOrExternCrate::ExternCrate),
535-
)
536-
},
537-
)
640+
self.resolve_name_in_extern_prelude(name)
538641
};
539642

540643
from_crate_root.or_else(from_extern_prelude)

src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs

+25
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,29 @@ self::m!(); self::m2!();
8282
"#,
8383
);
8484
}
85+
86+
#[test]
87+
fn no_unresolved_panic_inside_mod_inside_fn() {
88+
check_diagnostics(
89+
r#"
90+
//- /core.rs library crate:core
91+
#[macro_export]
92+
macro_rules! panic {
93+
() => {};
94+
}
95+
96+
//- /lib.rs crate:foo deps:core
97+
#[macro_use]
98+
extern crate core;
99+
100+
fn foo() {
101+
mod init {
102+
pub fn init() {
103+
panic!();
104+
}
105+
}
106+
}
107+
"#,
108+
);
109+
}
85110
}

0 commit comments

Comments
 (0)